Merge "Start uevent handling thread early" into qt-dev
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..fc4eb1b
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+AccessModifierOffset: -2
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java b/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java
index e64a306..f38bf65 100644
--- a/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java
+++ b/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java
@@ -18,19 +18,25 @@
import android.annotation.IntDef;
+import com.android.internal.annotations.VisibleForTesting;
+
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
+ * An encryption runner that doesn't actually do encryption. Useful for debugging. Do not use in
* production environments.
*/
-class DummyEncryptionRunner implements EncryptionRunner {
+@VisibleForTesting
+public 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";
+ @VisibleForTesting
+ public static final String INIT = "init";
+ @VisibleForTesting
+ public static final String INIT_RESPONSE = "initResponse";
+ @VisibleForTesting
+ public static final String CLIENT_RESPONSE = "clientResponse";
public static final String VERIFICATION_CODE = "1234";
@Retention(RetentionPolicy.SOURCE)
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java
index 23851b7..156abd8 100644
--- a/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java
+++ b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java
@@ -16,6 +16,8 @@
package android.car.encryptionrunner;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Factory that creates encryption runner.
*/
@@ -36,7 +38,8 @@
* Creates a new {@link EncryptionRunner} one that doesn't actually do encryption but is useful
* for testing.
*/
- static EncryptionRunner newDummyRunner() {
+ @VisibleForTesting
+ public static EncryptionRunner newDummyRunner() {
return new DummyEncryptionRunner();
}
}
diff --git a/FrameworkPackageStubs/AndroidManifest.xml b/FrameworkPackageStubs/AndroidManifest.xml
index c9eae62..89ea2b0 100644
--- a/FrameworkPackageStubs/AndroidManifest.xml
+++ b/FrameworkPackageStubs/AndroidManifest.xml
@@ -9,6 +9,17 @@
<application android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
+ <!-- Dialer stubs -->
+ <activity android:name=".Stubs$DialerStub"
+ android:label="@string/stub_name"
+ android:excludeFromRecents="true">
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.DIAL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="voicemail"/>
+ </intent-filter>
+ </activity>
+
<!-- Music / media stubs. -->
<activity android:name=".Stubs$MediaStub"
android:label="@string/stub_name"
@@ -63,10 +74,66 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:priority="-1">
+ <action android:name="android.settings.PROCESS_WIFI_EASY_CONNECT_URI" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="DPP"/>
+ </intent-filter>
+ <intent-filter android:priority="-1">
<action android:name="android.settings.USER_DICTIONARY_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+ <!-- CDD Core Application Intents Stubs -->
+ <!-- Desk Clock -->
+ <activity android:name=".Stubs$DeskClockStub"
+ android:label="@string/stub_name"
+ android:excludeFromRecents="true">
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.SET_ALARM" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.SET_TIMER" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.SHOW_ALARMS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.DISMISS_ALARM" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.SHOW_TIMERS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.SNOOZE_ALARM" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- Calendar -->
+ <activity android:name=".Stubs$CalendarStub"
+ android:label="@string/stub_name"
+ android:excludeFromRecents="true">
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.EDIT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="vnd.android.cursor.item/event" />
+ </intent-filter>
+ </activity>
+
+ <!-- Browser -->
+ <activity android:name=".Stubs$BrowserStub"
+ android:label="@string/stub_name"
+ android:excludeFromRecents="true">
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.WEB_SEARCH" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/FrameworkPackageStubs/src/com/android/car/frameworkpackagestubs/Stubs.java b/FrameworkPackageStubs/src/com/android/car/frameworkpackagestubs/Stubs.java
index 5ebcabd..056912a 100644
--- a/FrameworkPackageStubs/src/com/android/car/frameworkpackagestubs/Stubs.java
+++ b/FrameworkPackageStubs/src/com/android/car/frameworkpackagestubs/Stubs.java
@@ -64,6 +64,26 @@
}
/**
+ * Stub activity for Browser events.
+ */
+ public static class BrowserStub extends BaseActivity { }
+
+ /**
+ * Stub activity for Calendar events.
+ */
+ public static class CalendarStub extends BaseActivity { }
+
+ /**
+ * Stub activity for Desk Clock events.
+ */
+ public static class DeskClockStub extends BaseActivity { }
+
+ /**
+ * Stub activity for Dialer events.
+ */
+ public static class DialerStub extends BaseActivity { }
+
+ /**
* Stub activity for media events.
*/
public static class MediaStub extends BaseActivity { }
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d935103
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+Native (C++) code format is required to be compatible with .clang-format file. Run
+
+```
+git clang-format --style=file --extension='h,cpp,cc' HEAD~
+```
+
+Note that clang-format is *not* desirable for Android java files. Therefore
+the command line above is limited to specific extensions.
+
diff --git a/car-bugreportd/Android.bp b/car-bugreportd/Android.bp
new file mode 100644
index 0000000..e026d0b
--- /dev/null
+++ b/car-bugreportd/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+
+cc_binary {
+ name: "car-bugreportd",
+ init_rc: ["car-bugreportd.rc"],
+ srcs: [
+ "main.cpp",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+ cppflags: [
+ "-Wno-unused-parameter",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ ],
+}
diff --git a/car-bugreportd/car-bugreportd.rc b/car-bugreportd/car-bugreportd.rc
new file mode 100644
index 0000000..4c405e1
--- /dev/null
+++ b/car-bugreportd/car-bugreportd.rc
@@ -0,0 +1,17 @@
+service car-bugreportd /system/bin/car-bugreportd
+ socket car_br_progress_socket stream 0660 shell log
+ socket car_br_output_socket stream 0660 shell log
+ class core
+ user shell
+ group log
+ disabled
+ oneshot
+
+# car-dumpstatez generates a zipped bugreport but also uses a socket to print the file location once
+# it is finished.
+service car-dumpstatez /system/bin/dumpstate -S -d -z \
+ -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
+ socket dumpstate stream 0660 shell log
+ class main
+ disabled
+ oneshot
\ No newline at end of file
diff --git a/car-bugreportd/main.cpp b/car-bugreportd/main.cpp
new file mode 100644
index 0000000..055d35a
--- /dev/null
+++ b/car-bugreportd/main.cpp
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "car-bugreportd"
+
+#include <android-base/errors.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <log/log_main.h>
+#include <private/android_filesystem_config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <string>
+#include <vector>
+
+namespace {
+// Socket to write the progress information.
+constexpr const char* kCarBrProgressSocket = "car_br_progress_socket";
+// Socket to write the zipped bugreport file.
+constexpr const char* kCarBrOutputSocket = "car_br_output_socket";
+// The prefix used by bugreportz protocol to indicate bugreport finished successfully.
+constexpr const char* kOkPrefix = "OK:";
+// Number of connect attempts to dumpstate socket
+constexpr const int kMaxDumpstateConnectAttempts = 20;
+// Wait time between connect attempts
+constexpr const int kWaitTimeBetweenConnectAttemptsInSec = 1;
+// Wait time for dumpstate. No timeout in dumpstate is longer than 60 seconds. Choose
+// a value that is twice longer.
+constexpr const int kDumpstateTimeoutInSec = 120;
+
+// Returns a valid socket descriptor or -1 on failure.
+int openSocket(const char* service) {
+ int s = android_get_control_socket(service);
+ if (s < 0) {
+ ALOGE("android_get_control_socket(%s): %s", service, strerror(errno));
+ return -1;
+ }
+ fcntl(s, F_SETFD, FD_CLOEXEC);
+ if (listen(s, 4) < 0) {
+ ALOGE("listen(control socket): %s", strerror(errno));
+ return -1;
+ }
+
+ struct sockaddr addr;
+ socklen_t alen = sizeof(addr);
+ int fd = accept(s, &addr, &alen);
+ if (fd < 0) {
+ ALOGE("accept(control socket): %s", strerror(errno));
+ return -1;
+ }
+ return fd;
+}
+
+// Processes the given dumpstate progress protocol |line| and updates
+// |out_last_nonempty_line| when |line| is non-empty, and |out_zip_path| when
+// the bugreport is finished.
+void processLine(const std::string& line, std::string* out_zip_path,
+ std::string* out_last_nonempty_line) {
+ // The protocol is documented in frameworks/native/cmds/bugreportz/readme.md
+ if (line.empty()) {
+ return;
+ }
+ *out_last_nonempty_line = line;
+ if (line.find(kOkPrefix) != 0) {
+ return;
+ }
+ *out_zip_path = line.substr(strlen(kOkPrefix));
+ return;
+}
+
+int copyTo(int fd_in, int fd_out, void* buffer, size_t buffer_len) {
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd_in, buffer, buffer_len));
+ if (bytes_read == 0) {
+ return 0;
+ }
+ if (bytes_read == -1) {
+ // EAGAIN really means time out, so make that clear.
+ if (errno == EAGAIN) {
+ ALOGE("read timed out");
+ } else {
+ ALOGE("read terminated abnormally (%s)", strerror(errno));
+ }
+ return -1;
+ }
+ // copy all bytes to the output socket
+ if (!android::base::WriteFully(fd_out, buffer, bytes_read)) {
+ ALOGE("write failed");
+ return -1;
+ }
+ return bytes_read;
+}
+
+bool copyFile(const std::string& zip_path, int output_socket) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(zip_path.c_str(), O_RDONLY)));
+ if (fd == -1) {
+ return false;
+ }
+ while (1) {
+ char buffer[65536];
+ int bytes_copied = copyTo(fd, output_socket, buffer, sizeof(buffer));
+ if (bytes_copied == 0) {
+ break;
+ }
+ if (bytes_copied == -1) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Triggers a bugreport and waits until it is all collected.
+// returns false if error, true if success
+bool doBugreport(int progress_socket, size_t* out_bytes_written, std::string* zip_path) {
+ // Socket will not be available until service starts.
+ android::base::unique_fd s;
+ for (int i = 0; i < kMaxDumpstateConnectAttempts; i++) {
+ s.reset(socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
+ if (s != -1) break;
+ sleep(kWaitTimeBetweenConnectAttemptsInSec);
+ }
+
+ if (s == -1) {
+ ALOGE("failed to connect to dumpstatez service");
+ return false;
+ }
+
+ // Set a timeout so that if nothing is read by the timeout, stop reading and quit
+ struct timeval tv = {
+ .tv_sec = kDumpstateTimeoutInSec,
+ .tv_usec = 0,
+ };
+ if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) {
+ ALOGW("Cannot set socket timeout (%s)", strerror(errno));
+ }
+
+ std::string line;
+ std::string last_nonempty_line;
+ while (true) {
+ char buffer[65536];
+ ssize_t bytes_read = copyTo(s, progress_socket, buffer, sizeof(buffer));
+ if (bytes_read == 0) {
+ break;
+ }
+ if (bytes_read == -1) {
+ return false;
+ }
+ // Process the buffer line by line. this is needed for the filename.
+ for (int i = 0; i < bytes_read; i++) {
+ char c = buffer[i];
+ if (c == '\n') {
+ processLine(line, zip_path, &last_nonempty_line);
+ line.clear();
+ } else {
+ line.append(1, c);
+ }
+ }
+ }
+ s.reset();
+ // Process final line, in case it didn't finish with newline.
+ processLine(line, zip_path, &last_nonempty_line);
+ // if doBugReport finished successfully, zip path should be set.
+ if (zip_path->empty()) {
+ ALOGE("no zip file path was found in bugreportz progress data");
+ return false;
+ }
+ return true;
+}
+
+// Removes bugreport
+void cleanupBugreportFile(const std::string& zip_path) {
+ if (unlink(zip_path.c_str()) != 0) {
+ ALOGE("Could not unlink %s (%s)", zip_path.c_str(), strerror(errno));
+ }
+}
+
+} // namespace
+
+int main(void) {
+ ALOGE("Starting bugreport collecting service");
+
+ auto t0 = std::chrono::steady_clock::now();
+
+ // Start the dumpstatez service.
+ android::base::SetProperty("ctl.start", "car-dumpstatez");
+
+ size_t bytes_written = 0;
+
+ std::string zip_path;
+ int progress_socket = openSocket(kCarBrProgressSocket);
+ if (progress_socket < 0) {
+ // early out. in this case we will not print the final message, but that is ok.
+ android::base::SetProperty("ctl.stop", "car-dumpstatez");
+ return EXIT_FAILURE;
+ }
+ bool ret_val = doBugreport(progress_socket, &bytes_written, &zip_path);
+ close(progress_socket);
+
+ int output_socket = openSocket(kCarBrOutputSocket);
+ if (output_socket != -1 && ret_val) {
+ ret_val = copyFile(zip_path, output_socket);
+ }
+ if (output_socket != -1) {
+ close(output_socket);
+ }
+
+ auto delta = std::chrono::duration_cast<std::chrono::duration<double>>(
+ std::chrono::steady_clock::now() - t0)
+ .count();
+
+ std::string result = ret_val ? "success" : "failed";
+ ALOGI("bugreport %s in %.02fs, %zu bytes written", result.c_str(), delta, bytes_written);
+ cleanupBugreportFile(zip_path);
+
+ // No matter how doBugreport() finished, let's try to explicitly stop
+ // car-dumpstatez in case it stalled.
+ android::base::SetProperty("ctl.stop", "car-dumpstatez");
+
+ return ret_val ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/car-cluster-logging-renderer/Android.mk b/car-cluster-logging-renderer/Android.mk
deleted file mode 100644
index 5d88b48..0000000
--- a/car-cluster-logging-renderer/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-ifneq ($(TARGET_BUILD_PDK),true)
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := android.car.cluster.loggingrenderer
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# Each update should be signed by OEMs
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_JAVA_LIBRARIES += android.car
-
-LOCAL_STATIC_ANDROID_LIBRARIES += \
- androidx.car_car-cluster
-
-LOCAL_REQUIRED_MODULES := privapp_whitelist_android.car.cluster.loggingrenderer
-
-include $(BUILD_PACKAGE)
-endif
diff --git a/car-cluster-logging-renderer/AndroidManifest.xml b/car-cluster-logging-renderer/AndroidManifest.xml
deleted file mode 100644
index 81fa46d..0000000
--- a/car-cluster-logging-renderer/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.car.cluster.loggingrenderer"
- android:sharedUserId="android.uid.system"
- android:versionCode="1"
- android:versionName="1.0">
-
- <protected-broadcast android:name="android.car.cluster.NAVIGATION_STATE_UPDATE"/>
-
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
-
- <application android:label="@string/app_name"
- android:icon="@drawable/ic_launcher"
- android:directBootAware="true"
- android:persistent="true">
- <service android:name=".LoggingClusterRenderingService"
- android:exported="false"
- android:permission="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"
- />
- </application>
-</manifest>
diff --git a/car-cluster-logging-renderer/proguard.flags b/car-cluster-logging-renderer/proguard.flags
deleted file mode 100644
index 22cc22d..0000000
--- a/car-cluster-logging-renderer/proguard.flags
+++ /dev/null
@@ -1,3 +0,0 @@
--verbose
--keep @com.android.internal.annotations.VisibleForTesting class *
-
diff --git a/car-cluster-logging-renderer/res/values-am/strings.xml b/car-cluster-logging-renderer/res/values-am/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-am/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ar/strings.xml b/car-cluster-logging-renderer/res/values-ar/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ar/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-as/strings.xml b/car-cluster-logging-renderer/res/values-as/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-as/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-az/strings.xml b/car-cluster-logging-renderer/res/values-az/strings.xml
deleted file mode 100644
index a3ea5d3..0000000
--- a/car-cluster-logging-renderer/res/values-az/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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">"ALƏT_KLASTERİ_TƏCHİZATÇISI_GİRİŞİ"</string>
-</resources>
diff --git a/car-cluster-logging-renderer/res/values-b+sr+Latn/strings.xml b/car-cluster-logging-renderer/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-be/strings.xml b/car-cluster-logging-renderer/res/values-be/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-be/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-bg/strings.xml b/car-cluster-logging-renderer/res/values-bg/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-bg/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-bn/strings.xml b/car-cluster-logging-renderer/res/values-bn/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-bn/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-bs/strings.xml b/car-cluster-logging-renderer/res/values-bs/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-bs/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ca/strings.xml b/car-cluster-logging-renderer/res/values-ca/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ca/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-cs/strings.xml b/car-cluster-logging-renderer/res/values-cs/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-cs/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-da/strings.xml b/car-cluster-logging-renderer/res/values-da/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-da/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-de/strings.xml b/car-cluster-logging-renderer/res/values-de/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-de/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-el/strings.xml b/car-cluster-logging-renderer/res/values-el/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-el/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-en-rAU/strings.xml b/car-cluster-logging-renderer/res/values-en-rAU/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-en-rCA/strings.xml b/car-cluster-logging-renderer/res/values-en-rCA/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-en-rGB/strings.xml b/car-cluster-logging-renderer/res/values-en-rGB/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-en-rIN/strings.xml b/car-cluster-logging-renderer/res/values-en-rIN/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-en-rXC/strings.xml b/car-cluster-logging-renderer/res/values-en-rXC/strings.xml
deleted file mode 100644
index 9cf17c1..0000000
--- a/car-cluster-logging-renderer/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-es-rUS/strings.xml b/car-cluster-logging-renderer/res/values-es-rUS/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-es/strings.xml b/car-cluster-logging-renderer/res/values-es/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-es/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-et/strings.xml b/car-cluster-logging-renderer/res/values-et/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-et/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-eu/strings.xml b/car-cluster-logging-renderer/res/values-eu/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-eu/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-fa/strings.xml b/car-cluster-logging-renderer/res/values-fa/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-fa/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-fi/strings.xml b/car-cluster-logging-renderer/res/values-fi/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-fi/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-fr-rCA/strings.xml b/car-cluster-logging-renderer/res/values-fr-rCA/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-fr/strings.xml b/car-cluster-logging-renderer/res/values-fr/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-fr/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-gl/strings.xml b/car-cluster-logging-renderer/res/values-gl/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-gl/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-gu/strings.xml b/car-cluster-logging-renderer/res/values-gu/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-gu/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-hi/strings.xml b/car-cluster-logging-renderer/res/values-hi/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-hi/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-hr/strings.xml b/car-cluster-logging-renderer/res/values-hr/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-hr/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-hu/strings.xml b/car-cluster-logging-renderer/res/values-hu/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-hu/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-hy/strings.xml b/car-cluster-logging-renderer/res/values-hy/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-hy/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-in/strings.xml b/car-cluster-logging-renderer/res/values-in/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-in/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-is/strings.xml b/car-cluster-logging-renderer/res/values-is/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-is/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-it/strings.xml b/car-cluster-logging-renderer/res/values-it/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-it/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-iw/strings.xml b/car-cluster-logging-renderer/res/values-iw/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-iw/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ja/strings.xml b/car-cluster-logging-renderer/res/values-ja/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ja/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ka/strings.xml b/car-cluster-logging-renderer/res/values-ka/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ka/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-kk/strings.xml b/car-cluster-logging-renderer/res/values-kk/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-kk/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-km/strings.xml b/car-cluster-logging-renderer/res/values-km/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-km/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-kn/strings.xml b/car-cluster-logging-renderer/res/values-kn/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-kn/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ko/strings.xml b/car-cluster-logging-renderer/res/values-ko/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ko/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ky/strings.xml b/car-cluster-logging-renderer/res/values-ky/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ky/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-lo/strings.xml b/car-cluster-logging-renderer/res/values-lo/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-lo/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-lt/strings.xml b/car-cluster-logging-renderer/res/values-lt/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-lt/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-lv/strings.xml b/car-cluster-logging-renderer/res/values-lv/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-lv/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-mk/strings.xml b/car-cluster-logging-renderer/res/values-mk/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-mk/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ml/strings.xml b/car-cluster-logging-renderer/res/values-ml/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ml/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-mn/strings.xml b/car-cluster-logging-renderer/res/values-mn/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-mn/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-mr/strings.xml b/car-cluster-logging-renderer/res/values-mr/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-mr/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ms/strings.xml b/car-cluster-logging-renderer/res/values-ms/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ms/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-my/strings.xml b/car-cluster-logging-renderer/res/values-my/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-my/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-nb/strings.xml b/car-cluster-logging-renderer/res/values-nb/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-nb/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ne/strings.xml b/car-cluster-logging-renderer/res/values-ne/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ne/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-nl/strings.xml b/car-cluster-logging-renderer/res/values-nl/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-nl/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-or/strings.xml b/car-cluster-logging-renderer/res/values-or/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-or/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-pa/strings.xml b/car-cluster-logging-renderer/res/values-pa/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-pa/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-pl/strings.xml b/car-cluster-logging-renderer/res/values-pl/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-pl/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-pt-rPT/strings.xml b/car-cluster-logging-renderer/res/values-pt-rPT/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-pt/strings.xml b/car-cluster-logging-renderer/res/values-pt/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-pt/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ro/strings.xml b/car-cluster-logging-renderer/res/values-ro/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ro/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ru/strings.xml b/car-cluster-logging-renderer/res/values-ru/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ru/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-si/strings.xml b/car-cluster-logging-renderer/res/values-si/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-si/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-sk/strings.xml b/car-cluster-logging-renderer/res/values-sk/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-sk/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-sl/strings.xml b/car-cluster-logging-renderer/res/values-sl/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-sl/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-sq/strings.xml b/car-cluster-logging-renderer/res/values-sq/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-sq/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-sr/strings.xml b/car-cluster-logging-renderer/res/values-sr/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-sr/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-sv/strings.xml b/car-cluster-logging-renderer/res/values-sv/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-sv/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-sw/strings.xml b/car-cluster-logging-renderer/res/values-sw/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-sw/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ta/strings.xml b/car-cluster-logging-renderer/res/values-ta/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ta/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-te/strings.xml b/car-cluster-logging-renderer/res/values-te/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-te/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-th/strings.xml b/car-cluster-logging-renderer/res/values-th/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-th/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-tl/strings.xml b/car-cluster-logging-renderer/res/values-tl/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-tl/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-tr/strings.xml b/car-cluster-logging-renderer/res/values-tr/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-tr/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-uk/strings.xml b/car-cluster-logging-renderer/res/values-uk/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-uk/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-ur/strings.xml b/car-cluster-logging-renderer/res/values-ur/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-ur/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-uz/strings.xml b/car-cluster-logging-renderer/res/values-uz/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-uz/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-vi/strings.xml b/car-cluster-logging-renderer/res/values-vi/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-vi/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-zh-rCN/strings.xml b/car-cluster-logging-renderer/res/values-zh-rCN/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-zh-rHK/strings.xml b/car-cluster-logging-renderer/res/values-zh-rHK/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-zh-rTW/strings.xml b/car-cluster-logging-renderer/res/values-zh-rTW/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/res/values-zu/strings.xml b/car-cluster-logging-renderer/res/values-zu/strings.xml
deleted file mode 100644
index daa61a3..0000000
--- a/car-cluster-logging-renderer/res/values-zu/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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-cluster-logging-renderer/src/android/car/cluster/loggingrenderer/LoggingClusterRenderingService.java b/car-cluster-logging-renderer/src/android/car/cluster/loggingrenderer/LoggingClusterRenderingService.java
deleted file mode 100644
index c42ea5e..0000000
--- a/car-cluster-logging-renderer/src/android/car/cluster/loggingrenderer/LoggingClusterRenderingService.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.loggingrenderer;
-
-import android.car.cluster.renderer.InstrumentClusterRenderingService;
-import android.car.cluster.renderer.NavigationRenderer;
-import android.car.navigation.CarNavigationInstrumentCluster;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.util.Log;
-
-import androidx.car.cluster.navigation.NavigationState;
-import androidx.versionedparcelable.ParcelUtils;
-
-import com.google.android.collect.Lists;
-
-/**
- * Dummy implementation of {@link LoggingClusterRenderingService} to log all interaction.
- */
-public class LoggingClusterRenderingService extends InstrumentClusterRenderingService {
- private static final String TAG = LoggingClusterRenderingService.class.getSimpleName();
- private static final String NAV_STATE_BUNDLE_KEY = "navstate";
- private static final int NAV_STATE_EVENT_ID = 1;
-
- @Override
- public NavigationRenderer getNavigationRenderer() {
- NavigationRenderer navigationRenderer = new NavigationRenderer() {
- @Override
- public CarNavigationInstrumentCluster getNavigationProperties() {
- Log.i(TAG, "getNavigationProperties");
- CarNavigationInstrumentCluster config =
- CarNavigationInstrumentCluster.createCluster(1000);
- config.getExtra().putIntegerArrayList("dummy", Lists.newArrayList(1, 2, 3, 4));
- Log.i(TAG, "getNavigationProperties, returns: " + config);
- return config;
- }
-
- @Override
- public void onEvent(int eventType, Bundle bundle) {
- StringBuilder bundleSummary = new StringBuilder();
- if (eventType == NAV_STATE_EVENT_ID) {
- bundle.setClassLoader(ParcelUtils.class.getClassLoader());
- NavigationState navState = NavigationState
- .fromParcelable(bundle.getParcelable(NAV_STATE_BUNDLE_KEY));
- bundleSummary.append(navState.toString());
-
- // Sending broadcast for testing.
- Intent intent = new Intent("android.car.cluster.NAVIGATION_STATE_UPDATE");
- intent.putExtra(NAV_STATE_BUNDLE_KEY, bundle);
- sendBroadcastAsUser(intent, UserHandle.ALL);
- } else {
- for (String key : bundle.keySet()) {
- bundleSummary.append(key);
- bundleSummary.append("=");
- bundleSummary.append(bundle.get(key));
- bundleSummary.append(" ");
- }
- }
- Log.i(TAG, "onEvent(" + eventType + ", " + bundleSummary + ")");
- }
- };
-
- Log.i(TAG, "createNavigationRenderer, returns: " + navigationRenderer);
- return navigationRenderer;
- }
-}
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index d6b162e..515bd93 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -7,6 +7,14 @@
}
+package android.car.drivingstate {
+
+ public final class CarDrivingStateManager {
+ method public void injectDrivingState(int);
+ }
+
+}
+
package android.car.media {
public final class CarAudioManager {
diff --git a/car-lib/src/android/car/CarBugreportManager.java b/car-lib/src/android/car/CarBugreportManager.java
index 07e9c5d..7fca8ba 100644
--- a/car-lib/src/android/car/CarBugreportManager.java
+++ b/car-lib/src/android/car/CarBugreportManager.java
@@ -139,25 +139,32 @@
}
/**
- * Request a bug report. An old style flat bugreport is generated in the background.
- * The fd is closed when bugreport is written or if an exception happens.
+ * Request a bug report. An zipped bugreport is generated in the background.
+ * The file descriptors are closed when bugreport is written or if an exception happens.
+ * The progress protocol is described
+ * <a href="https://android.googlesource.com/platform/frameworks/native/+/master/cmds/bugreportz/readme.md">
+ * here</a>
*
- * @param fd the dump file
+ * @param output the zipped bugreport file
+ * @param progress the progress information that includes failure/success status.
* @param callback the callback for reporting dump status
*/
@RequiresPermission(android.Manifest.permission.DUMP)
- public void requestBugreport(@NonNull ParcelFileDescriptor fd,
+ public void requestZippedBugreport(@NonNull ParcelFileDescriptor output,
+ @NonNull ParcelFileDescriptor progress,
@NonNull CarBugreportManagerCallback callback) {
+ Preconditions.checkNotNull(output);
+ Preconditions.checkNotNull(progress);
+ Preconditions.checkNotNull(callback);
try {
- Preconditions.checkNotNull(fd);
- Preconditions.checkNotNull(callback);
CarBugreportManagerCallbackWrapper wrapper =
new CarBugreportManagerCallbackWrapper(callback, mHandler);
- mService.requestBugreport(fd, wrapper);
+ mService.requestZippedBugreport(output, progress, wrapper);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} finally {
- IoUtils.closeQuietly(fd);
+ IoUtils.closeQuietly(output);
+ IoUtils.closeQuietly(progress);
}
}
diff --git a/car-lib/src/android/car/ICarBugreportService.aidl b/car-lib/src/android/car/ICarBugreportService.aidl
index 9f20081..2d713da 100644
--- a/car-lib/src/android/car/ICarBugreportService.aidl
+++ b/car-lib/src/android/car/ICarBugreportService.aidl
@@ -26,7 +26,16 @@
interface ICarBugreportService {
/**
- * Starts bugreport service to capture a bugreport
+ * Starts bugreport service to capture a zipped bugreport. The caller needs to provide
+ * two file descriptors. The "output" file descriptor will be used to provide the actual
+ * zip file and the "progress" descriptor will be used to provide the progress information.
+ * Both of these descriptors are written by the service and will be read by the client.
+ *
+ * The progress protocol is described
+ * <a href="https://android.googlesource.com/platform/frameworks/native/+/master/cmds/bugreportz/readme.md">
+ * here</a>
*/
- void requestBugreport(in ParcelFileDescriptor pfd, ICarBugreportCallback callback) = 1;
- }
\ No newline at end of file
+ void requestZippedBugreport(in ParcelFileDescriptor output, in ParcelFileDescriptor progress,
+ ICarBugreportCallback callback) = 1;
+ }
+
diff --git a/car-lib/src/android/car/VehiclePropertyIds.java b/car-lib/src/android/car/VehiclePropertyIds.java
index 14642fe..c335e58 100644
--- a/car-lib/src/android/car/VehiclePropertyIds.java
+++ b/car-lib/src/android/car/VehiclePropertyIds.java
@@ -28,55 +28,68 @@
public static final int INVALID = 0;
/**
* VIN of vehicle
+ * Requires permission: {@link Car#PERMISSION_IDENTIFICATION}.
*/
public static final int INFO_VIN = 286261504;
/**
* Manufacturer of vehicle
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_MAKE = 286261505;
/**
* Model of vehicle
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_MODEL = 286261506;
/**
* Model year of vehicle.
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_MODEL_YEAR = 289407235;
/**
* Fuel capacity of the vehicle in milliliters
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_FUEL_CAPACITY = 291504388;
/**
* List of fuels the vehicle may use
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_FUEL_TYPE = 289472773;
/**
* Battery capacity of the vehicle, if EV or hybrid. This is the nominal
* battery capacity when the vehicle is new.
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_EV_BATTERY_CAPACITY = 291504390;
/**
* List of connectors this EV may use
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_EV_CONNECTOR_TYPE = 289472775;
/**
* Fuel door location
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_FUEL_DOOR_LOCATION = 289407240;
/**
* EV port location
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_EV_PORT_LOCATION = 289407241;
/**
* Driver's seat location
+ * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
public static final int INFO_DRIVER_SEAT = 356516106;
/**
* Current odometer value of the vehicle
+ * Requires permission: {@link Car#PERMISSION_MILEAGE}.
*/
public static final int PERF_ODOMETER = 291504644;
/**
* Speed of the vehicle
+ * Requires permission: {@link Car#PERMISSION_SPEED}.
*/
public static final int PERF_VEHICLE_SPEED = 291504647;
/**
@@ -84,60 +97,74 @@
*
* Some cars display a slightly slower speed than the actual speed. This is
* usually displayed on the speedometer.
+ * Requires permission: {@link Car#PERMISSION_SPEED}.
*/
public static final int PERF_VEHICLE_SPEED_DISPLAY = 291504648;
/**
* Steering angle of the vehicle
*
* Angle is in degrees. Left is negative.
+ * Requires permission: {@link Car#PERMISSION_READ_STEERING_STATE}.
*/
public static final int PERF_STEERING_ANGLE = 291504649;
/**
* Temperature of engine coolant
+ * Requires permission: {@link Car#PERMISSION_CAR_ENGINE_DETAILED}.
*/
public static final int ENGINE_COOLANT_TEMP = 291504897;
/**
* Engine oil level
+ * Requires permission: {@link Car#PERMISSION_CAR_ENGINE_DETAILED}.
*/
public static final int ENGINE_OIL_LEVEL = 289407747;
/**
* Temperature of engine oil
+ * Requires permission: {@link Car#PERMISSION_CAR_ENGINE_DETAILED}.
*/
public static final int ENGINE_OIL_TEMP = 291504900;
/**
* Engine rpm
+ * Requires permission: {@link Car#PERMISSION_CAR_ENGINE_DETAILED}.
*/
public static final int ENGINE_RPM = 291504901;
/**
* Reports wheel ticks
+ * Requires permission: {@link Car#PERMISSION_SPEED}.
*/
public static final int WHEEL_TICK = 290521862;
/**
* Fuel remaining in the the vehicle, in milliliters
+ * Requires permission: {@link Car#PERMISSION_ENERGY}.
*/
public static final int FUEL_LEVEL = 291504903;
/**
* Fuel door open
+ * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS}.
*/
public static final int FUEL_DOOR_OPEN = 287310600;
/**
* EV battery level in WH, if EV or hybrid
+ * Requires permission: {@link Car#PERMISSION_ENERGY}.
*/
public static final int EV_BATTERY_LEVEL = 291504905;
/**
* EV charge port open
+ * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS}.
*/
public static final int EV_CHARGE_PORT_OPEN = 287310602;
/**
* EV charge port connected
+ * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS}.
*/
public static final int EV_CHARGE_PORT_CONNECTED = 287310603;
/**
* EV instantaneous charge rate in milliwatts
+ * Requires permission: {@link Car#PERMISSION_ENERGY}.
*/
public static final int EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 291504908;
/**
* Range remaining
+ * Requires permission: {@link Car#PERMISSION_ENERGY}.
*/
public static final int RANGE_REMAINING = 291504904;
/**
@@ -145,12 +172,14 @@
*
* min/max value indicates tire pressure sensor range. Each tire will have a separate min/max
* value denoted by its areaConfig.areaId.
+ * Requires permission: {@link Car#PERMISSION_TIRES}.
*/
public static final int TIRE_PRESSURE = 392168201;
/**
* Currently selected gear
*
* This is the gear selected by the user.
+ * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
*/
public static final int GEAR_SELECTION = 289408000;
/**
@@ -158,103 +187,127 @@
* match the current gear. For example, if the selected gear is GEAR_DRIVE,
* the current gear will be one of GEAR_1, GEAR_2 etc, which reflects
* the actual gear the transmission is currently running in.
+ * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
*/
public static final int CURRENT_GEAR = 289408001;
/**
* Parking brake state.
+ * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
*/
public static final int PARKING_BRAKE_ON = 287310850;
/**
* Auto-apply parking brake.
+ * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
*/
public static final int PARKING_BRAKE_AUTO_APPLY = 287310851;
/**
* Warning for fuel low level.
+ * Requires permission: {@link Car#PERMISSION_ENERGY}.
*/
public static final int FUEL_LEVEL_LOW = 287310853;
/**
* Night mode
+ * Requires permission: {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT}.
*/
public static final int NIGHT_MODE = 287310855;
/**
* State of the vehicles turn signals
+ * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
*/
public static final int TURN_SIGNAL_STATE = 289408008;
/**
* Represents ignition state
+ * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
*/
public static final int IGNITION_STATE = 289408009;
/**
* ABS is active
+ * Requires permission: {@link Car#PERMISSION_CAR_DYNAMICS_STATE}.
*/
public static final int ABS_ACTIVE = 287310858;
/**
* Traction Control is active
+ * Requires permission: {@link Car#PERMISSION_CAR_DYNAMICS_STATE}.
*/
public static final int TRACTION_CONTROL_ACTIVE = 287310859;
/**
* Fan speed setting
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_FAN_SPEED = 356517120;
/**
* Fan direction setting
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_FAN_DIRECTION = 356517121;
/**
* HVAC current temperature.
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_TEMPERATURE_CURRENT = 358614274;
/**
* HVAC, target temperature set.
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_TEMPERATURE_SET = 358614275;
/**
* On/off defrost for designated window
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_DEFROSTER = 320865540;
/**
* On/off AC for designated areaId
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_AC_ON = 354419973;
/**
* On/off max AC
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_MAX_AC_ON = 354419974;
/**
* On/off max defrost
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_MAX_DEFROST_ON = 354419975;
/**
* Recirculation on/off
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_RECIRC_ON = 354419976;
/**
* Enable temperature coupling between areas.
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_DUAL_ON = 354419977;
/**
* On/off automatic mode
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_AUTO_ON = 354419978;
/**
* Seat heating/cooling
- *
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_SEAT_TEMPERATURE = 356517131;
/**
* Side Mirror Heat
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_SIDE_MIRROR_HEAT = 339739916;
/**
* Steering Wheel Heating/Cooling
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_STEERING_WHEEL_HEAT = 289408269;
/**
* Temperature units for display
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_TEMPERATURE_DISPLAY_UNITS = 289408270;
/**
* Actual fan speed
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_ACTUAL_FAN_SPEED_RPM = 356517135;
/**
@@ -264,47 +317,64 @@
* properties that control individual HVAC features/subsystems to AVAILABLE
* state (unless any/all of them are UNAVAILABLE on their own individual
* merits).
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_POWER_ON = 354419984;
/**
* Fan Positions Available
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_FAN_DIRECTION_AVAILABLE = 356582673;
/**
* Automatic recirculation on/off
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_AUTO_RECIRC_ON = 354419986;
/**
* Seat ventilation
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
*/
public static final int HVAC_SEAT_VENTILATION = 356517139;
/**
* Distance units for display
+ * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
+ * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} to write the property.
*/
public static final int DISTANCE_DISPLAY_UNITS = 289408512;
/**
* Fuel volume units for display
+ * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
+ * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} to write the property.
*/
public static final int FUEL_VOLUME_DISPLAY_UNITS = 289408513;
/**
* Tire pressure units for display
+ * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
+ * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} to write the property.
*/
public static final int TIRE_PRESSURE_DISPLAY_UNITS = 289408514;
/**
* EV battery units for display
+ * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
+ * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} to write the property.
*/
public static final int EV_BATTERY_DISPLAY_UNITS = 289408515;
/**
* Speed Units for display
+ * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
+ * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} to write the property.
* @hide
*/
public static final int VEHICLE_SPEED_DISPLAY_UNITS = 289408516;
/**
* Fuel consumption units for display
+ * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
+ * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} to write the property.
*/
public static final int FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364;
/**
* Outside temperature
+ * Requires permission: {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT}.
*/
public static final int ENV_OUTSIDE_TEMPERATURE = 291505923;
/**
@@ -312,6 +382,7 @@
*
* It is assumed that AP's power state is controller by separate power
* controller.
+ * Requires permission: {@link Car#PERMISSION_CAR_POWER}.
*/
public static final int AP_POWER_STATE_REQ = 289475072;
/**
@@ -319,6 +390,7 @@
*
* It is assumed that AP's power state is controller by separate power
* controller.
+ * Requires permission: {@link Car#PERMISSION_CAR_POWER}.
*/
public static final int AP_POWER_STATE_REPORT = 289475073;
/**
@@ -327,12 +399,14 @@
* off. For example, even if user presses power on button after automatic
* power on with door unlock, bootup reason must stay with
* VehicleApPowerBootupReason#USER_UNLOCK.
+ * Requires permission: {@link Car#PERMISSION_CAR_POWER}.
*/
public static final int AP_POWER_BOOTUP_REASON = 289409538;
/**
* Property to represent brightness of the display. Some cars have single
* control for the brightness of all displays and this property is to share
* change in that control.
+ * Requires permission: {@link Car#PERMISSION_CAR_POWER}.
*/
public static final int DISPLAY_BRIGHTNESS = 289409539;
/**
@@ -344,38 +418,47 @@
*
* This is an integer in case a door may be set to a particular position.
* Max value indicates fully open, min value (0) indicates fully closed.
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_DOORS}.
*/
public static final int DOOR_POS = 373295872;
/**
* Door move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_DOORS}.
*/
public static final int DOOR_MOVE = 373295873;
/**
* Door lock
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_DOORS}.
*/
public static final int DOOR_LOCK = 371198722;
/**
* Mirror Z Position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
*/
public static final int MIRROR_Z_POS = 339741504;
/**
* Mirror Z Move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
*/
public static final int MIRROR_Z_MOVE = 339741505;
/**
* Mirror Y Position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
*/
public static final int MIRROR_Y_POS = 339741506;
/**
* Mirror Y Move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
*/
public static final int MIRROR_Y_MOVE = 339741507;
/**
* Mirror Lock
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
*/
public static final int MIRROR_LOCK = 287312708;
/**
* Mirror Fold
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
*/
public static final int MIRROR_FOLD = 287312709;
/**
@@ -384,6 +467,7 @@
* This parameter selects the memory preset to use to select the seat
* position. The minValue is always 0, and the maxValue determines the
* number of seat positions available.
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_MEMORY_SELECT = 356518784;
/**
@@ -392,136 +476,169 @@
* This setting allows the user to save the current seat position settings
* into the selected preset slot. The maxValue for each seat position
* must match the maxValue for SEAT_MEMORY_SELECT.
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_MEMORY_SET = 356518785;
/**
* Seatbelt buckled
*
* True indicates belt is buckled.
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_BELT_BUCKLED = 354421634;
/**
* Seatbelt height position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_BELT_HEIGHT_POS = 356518787;
/**
* Seatbelt height move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_BELT_HEIGHT_MOVE = 356518788;
/**
* Seat fore/aft position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_FORE_AFT_POS = 356518789;
/**
* Seat fore/aft move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_FORE_AFT_MOVE = 356518790;
/**
* Seat backrest angle 1 position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_BACKREST_ANGLE_1_POS = 356518791;
/**
* Seat backrest angle 1 move
*
* Moves the backrest forward or recline.
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_BACKREST_ANGLE_1_MOVE = 356518792;
/**
* Seat backrest angle 2 position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_BACKREST_ANGLE_2_POS = 356518793;
/**
* Seat backrest angle 2 move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_BACKREST_ANGLE_2_MOVE = 356518794;
/**
* Seat height position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_HEIGHT_POS = 356518795;
/**
* Seat height move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_HEIGHT_MOVE = 356518796;
/**
* Seat depth position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_DEPTH_POS = 356518797;
/**
* Seat depth move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_DEPTH_MOVE = 356518798;
/**
* Seat tilt position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_TILT_POS = 356518799;
/**
* Seat tilt move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_TILT_MOVE = 356518800;
/**
* Lumber fore/aft position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_LUMBAR_FORE_AFT_POS = 356518801;
/**
* Lumbar fore/aft move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_LUMBAR_FORE_AFT_MOVE = 356518802;
/**
* Lumbar side support position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803;
/**
* Lumbar side support move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804;
/**
* Headrest height position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_HEADREST_HEIGHT_POS = 289409941;
/**
* Headrest height move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_HEADREST_HEIGHT_MOVE = 356518806;
/**
* Headrest angle position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_HEADREST_ANGLE_POS = 356518807;
/**
* Headrest angle move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_HEADREST_ANGLE_MOVE = 356518808;
/**
* Headrest fore/aft position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_HEADREST_FORE_AFT_POS = 356518809;
/**
* Headrest fore/aft move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_HEADREST_FORE_AFT_MOVE = 356518810;
/**
* Seat Occupancy
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
*/
public static final int SEAT_OCCUPANCY = 356518832;
/**
* Window Position
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_WINDOWS}.
*/
public static final int WINDOW_POS = 322964416;
/**
* Window Move
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_WINDOWS}.
*/
public static final int WINDOW_MOVE = 322964417;
/**
* Window Lock
+ * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_WINDOWS}.
*/
public static final int WINDOW_LOCK = 320867268;
/**
* Vehicle Maps Service (VMS) message
+ * Requires one of permissions in {@link Car#PERMISSION_VMS_PUBLISHER},
+ * {@link Car#PERMISSION_VMS_SUBSCRIBER}.
*/
public static final int VEHICLE_MAP_SERVICE = 299895808;
/**
* OBD2 Live Sensor Data
*
* Reports a snapshot of the current (live) values of the OBD2 sensors available.
+ * Requires permission: {@link Car#PERMISSION_CAR_DIAGNOSTIC_READ_ALL}.
*/
public static final int OBD2_LIVE_FRAME = 299896064;
/**
@@ -529,10 +646,12 @@
*
* Reports a snapshot of the value of the OBD2 sensors available at the time that a fault
* occurred and was detected.
+ * Requires permission: {@link Car#PERMISSION_CAR_DIAGNOSTIC_READ_ALL}.
*/
public static final int OBD2_FREEZE_FRAME = 299896065;
/**
* OBD2 Freeze Frame Information
+ * Requires permission: {@link Car#PERMISSION_CAR_DIAGNOSTIC_READ_ALL}.
*/
public static final int OBD2_FREEZE_FRAME_INFO = 299896066;
/**
@@ -540,54 +659,67 @@
*
* This property allows deletion of any of the freeze frames stored in
* vehicle memory, as described by OBD2_FREEZE_FRAME_INFO.
+ * Requires permission: {@link Car#PERMISSION_CAR_DIAGNOSTIC_CLEAR}.
*/
public static final int OBD2_FREEZE_FRAME_CLEAR = 299896067;
/**
* Headlights State
+ * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
*/
public static final int HEADLIGHTS_STATE = 289410560;
/**
* High beam lights state
+ * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
*/
public static final int HIGH_BEAM_LIGHTS_STATE = 289410561;
/**
* Fog light state
+ * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
*/
public static final int FOG_LIGHTS_STATE = 289410562;
/**
* Hazard light status
+ * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
*/
public static final int HAZARD_LIGHTS_STATE = 289410563;
/**
* Headlight switch
+ * Requires permission: {@link Car#PERMISSION_CONTROL_EXTERIOR_LIGHTS}.
*/
public static final int HEADLIGHTS_SWITCH = 289410576;
/**
* High beam light switch
+ * Requires permission: {@link Car#PERMISSION_CONTROL_EXTERIOR_LIGHTS}.
*/
public static final int HIGH_BEAM_LIGHTS_SWITCH = 289410577;
/**
* Fog light switch
+ * Requires permission: {@link Car#PERMISSION_CONTROL_EXTERIOR_LIGHTS}.
*/
public static final int FOG_LIGHTS_SWITCH = 289410578;
/**
* Hazard light switch
+ * Requires permission: {@link Car#PERMISSION_CONTROL_EXTERIOR_LIGHTS}.
*/
public static final int HAZARD_LIGHTS_SWITCH = 289410579;
/**
* Cabin lights
+ * Requires permission: {@link Car#PERMISSION_READ_INTERIOR_LIGHTS}.
*/
public static final int CABIN_LIGHTS_STATE = 289410817;
/**
* Cabin lights switch
+ * Requires permission: {@link Car#PERMISSION_CONTROL_INTERIOR_LIGHTS}.
*/
public static final int CABIN_LIGHTS_SWITCH = 289410818;
/**
* Reading lights
+ * Requires permission: {@link Car#PERMISSION_READ_INTERIOR_LIGHTS}.
*/
public static final int READING_LIGHTS_STATE = 356519683;
/**
* Reading lights switch
+ * Requires permission: {@link Car#PERMISSION_CONTROL_INTERIOR_LIGHTS}.
*/
public static final int READING_LIGHTS_SWITCH = 356519684;
diff --git a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
index 896534a..9b0626f 100644
--- a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
+++ b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.car.Car;
import android.car.CarManagerBase;
import android.content.Context;
import android.os.Handler;
@@ -26,15 +28,18 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.Log;
import java.lang.ref.WeakReference;
/**
* API to register and get driving state related information in a car.
+ *
* @hide
*/
@SystemApi
+@TestApi
public final class CarDrivingStateManager implements CarManagerBase {
private static final String TAG = "CarDrivingStateMgr";
private static final boolean DBG = false;
@@ -64,7 +69,10 @@
/**
* Listener Interface for clients to implement to get updated on driving state changes.
+ *
+ * @hide
*/
+ @SystemApi
public interface CarDrivingStateEventListener {
/**
* Called when the car's driving state changes.
@@ -77,7 +85,10 @@
* Register a {@link CarDrivingStateEventListener} to listen for driving state changes.
*
* @param listener {@link CarDrivingStateEventListener}
+ *
+ * @hide
*/
+ @SystemApi
public synchronized void registerListener(@NonNull CarDrivingStateEventListener listener) {
if (listener == null) {
if (VDBG) {
@@ -107,7 +118,10 @@
/**
* Unregister the registered {@link CarDrivingStateEventListener} for the given driving event
* type.
+ *
+ * @hide
*/
+ @SystemApi
public synchronized void unregisterListener() {
if (mDrvStateEventListener == null) {
if (DBG) {
@@ -128,8 +142,11 @@
* Get the current value of the car's driving state.
*
* @return {@link CarDrivingStateEvent} corresponding to the given eventType
+ *
+ * @hide
*/
@Nullable
+ @SystemApi
public CarDrivingStateEvent getCurrentCarDrivingState() {
try {
return mDrivingService.getCurrentDrivingState();
@@ -139,6 +156,27 @@
}
/**
+ * Notify registered driving state change listener about injected event.
+ *
+ * @param drivingState Value in {@link CarDrivingStateEvent.CarDrivingState}.
+ *
+ * Requires Permission:
+ * {@link Car#PERMISSION_CONTROL_APP_BLOCKING}
+ *
+ * @hide
+ */
+ @TestApi
+ public void injectDrivingState(int drivingState) {
+ CarDrivingStateEvent event = new CarDrivingStateEvent(
+ drivingState, SystemClock.elapsedRealtimeNanos());
+ try {
+ mDrivingService.injectDrivingState(event);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* 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/ICarDrivingState.aidl b/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl
index 30f1542..23c5d03 100644
--- a/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl
+++ b/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl
@@ -31,4 +31,5 @@
void registerDrivingStateChangeListener(in ICarDrivingStateChangeListener listener) = 0;
void unregisterDrivingStateChangeListener(in ICarDrivingStateChangeListener listener) = 1;
CarDrivingStateEvent getCurrentDrivingState() = 2;
+ void injectDrivingState(in CarDrivingStateEvent event) = 3;
}
diff --git a/car-lib/src/android/car/media/CarAudioManager.java b/car-lib/src/android/car/media/CarAudioManager.java
index 6c2e1cd..c3338a9 100644
--- a/car-lib/src/android/car/media/CarAudioManager.java
+++ b/car-lib/src/android/car/media/CarAudioManager.java
@@ -412,6 +412,71 @@
}
/**
+ * Gets the audio zones currently available
+ *
+ * @return audio zone ids
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
+ public @NonNull int[] getAudioZoneIds() {
+ try {
+ return mService.getAudioZoneIds();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the audio zone id currently mapped to uId,
+ * defaults to PRIMARY_AUDIO_ZONE if no mapping exist
+ *
+ * @param uid The uid to map
+ * @return zone id mapped to uid
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
+ public int getZoneIdForUid(int uid) {
+ try {
+ return mService.getZoneIdForUid(uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Maps the audio zone id to uid
+ *
+ * @param zoneId The audio zone id
+ * @param uid The uid to map
+ * @return true if the uid is successfully mapped
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
+ public boolean setZoneIdForUid(int zoneId, int uid) {
+ try {
+ return mService.setZoneIdForUid(zoneId, uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Clears the current zone mapping of the uid
+ *
+ * @param uid The uid to clear
+ * @return true if the zone was successfully cleared
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
+ public boolean clearZoneIdForUid(int uid) {
+ try {
+ return mService.clearZoneIdForUid(uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Gets array of {@link AudioAttributes} usages for a volume group in a zone.
*
* @param zoneId The zone id whose volume group is queried.
diff --git a/car-lib/src/android/car/media/ICarAudio.aidl b/car-lib/src/android/car/media/ICarAudio.aidl
index 178f75a..a2f33ad 100644
--- a/car-lib/src/android/car/media/ICarAudio.aidl
+++ b/car-lib/src/android/car/media/ICarAudio.aidl
@@ -43,6 +43,11 @@
int getVolumeGroupIdForUsage(int zoneId, int usage);
int[] getUsagesForVolumeGroupId(int zoneId, int groupId);
+ int[] getAudioZoneIds();
+ int getZoneIdForUid(int uid);
+ boolean setZoneIdForUid(int zoneId, int uid);
+ boolean clearZoneIdForUid(int uid);
+
/**
* IBinder is ICarVolumeCallback but passed as IBinder due to aidl hidden.
*/
diff --git a/car_product/build/car.mk b/car_product/build/car.mk
index 66577be..bc67df9 100644
--- a/car_product/build/car.mk
+++ b/car_product/build/car.mk
@@ -35,12 +35,12 @@
# This is for testing
ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
PRODUCT_PACKAGES += \
+ BugReportApp \
DefaultStorageMonitoringCompanionApp \
EmbeddedKitchenSinkApp \
VmsPublisherClientSample \
VmsSubscriberClientSample \
- android.car.cluster.loggingrenderer \
- DirectRenderingClusterSample \
+ DirectRenderingCluster \
GarageModeTestApp \
# SEPolicy for test apps / services
diff --git a/car_product/build/car_base.mk b/car_product/build/car_base.mk
index 385a2ea..5132890 100644
--- a/car_product/build/car_base.mk
+++ b/car_product/build/car_base.mk
@@ -53,7 +53,8 @@
libwebrtc_audio_preprocessing \
wifi-service \
A2dpSinkService \
- PackageInstaller
+ PackageInstaller \
+ car-bugreportd \
# EVS resources
PRODUCT_PACKAGES += android.automotive.evs.manager@1.0
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-night/colors_device_defaults.xml b/car_product/overlay/frameworks/base/core/res/res/values-night/colors_device_defaults.xml
new file mode 100644
index 0000000..f062f1f
--- /dev/null
+++ b/car_product/overlay/frameworks/base/core/res/res/values-night/colors_device_defaults.xml
@@ -0,0 +1,23 @@
+<?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>
+ <color name="background_floating_device_default_dark">@*android:color/car_grey_900</color>
+ <color name="background_floating_device_default_light">@*android:color/car_grey_900</color>
+</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/colors_device_defaults.xml b/car_product/overlay/frameworks/base/core/res/res/values/colors_device_defaults.xml
index 2cd2d1f..7e2c329 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/colors_device_defaults.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/colors_device_defaults.xml
@@ -42,8 +42,8 @@
<color name="background_device_default_dark">@*android:color/car_background</color>
<color name="background_device_default_light">@*android:color/car_background</color>
- <color name="background_floating_device_default_dark">@*android:color/car_colorSecondary</color>
- <color name="background_floating_device_default_light">@*android:color/car_colorSecondary</color>
+ <color name="background_floating_device_default_dark">@*android:color/car_grey_868</color>
+ <color name="background_floating_device_default_light">@*android:color/car_grey_868</color>
<color name="error_color_device_default_dark">@*android:color/car_red_a700</color>
<color name="error_color_device_default_light">@*android:color/car_red_a700</color>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/config.xml b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
index 1d90073..6db7961 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
@@ -48,6 +48,7 @@
<!-- Allow smart unlock immediately after boot because the user shouldn't have to enter a pin
code to unlock their car head unit. -->
<bool name="config_strongAuthRequiredOnBoot">false</bool>
+ <string name="config_defaultTrustAgent" translatable="false">com.android.car/com.android.car.trust.CarBleTrustAgent</string>
<!-- Show Navigation Bar -->
<bool name="config_showNavigationBar">true</bool>
@@ -79,4 +80,9 @@
<!-- Whether the system enables per-display focus. If the system has the input method for each
display, this value should be true. -->
<bool name="config_perDisplayFocusEnabled">true</bool>
+
+ <!-- True if the device supports split screen as a form of multi-window. -->
+ <bool name="config_supportsSplitScreenMultiWindow">false</bool>
+
+ <string name="config_dataUsageSummaryComponent">com.android.car.settings/com.android.car.settings.datausage.DataWarningAndLimitActivity</string>
</resources>
diff --git a/car_product/sepolicy/private/carservice_app.te b/car_product/sepolicy/private/carservice_app.te
index 3c72a79..4f8315a 100644
--- a/car_product/sepolicy/private/carservice_app.te
+++ b/car_product/sepolicy/private/carservice_app.te
@@ -3,6 +3,7 @@
# Allow Car Service to be the client of Vehicle and Audio Control HALs
hal_client_domain(carservice_app, hal_audiocontrol)
+hal_client_domain(carservice_app, hal_health)
hal_client_domain(carservice_app, hal_vehicle)
# Allow to set boot.car_service_created property
@@ -11,6 +12,8 @@
# Allow Car Service to register itself with ServiceManager
allow carservice_app carservice_service:service_manager add;
+allow carservice_app wifi_service:service_manager find;
+
# Allow Car Service to access certain system services.
# Keep alphabetically sorted.
allow carservice_app {
@@ -46,6 +49,8 @@
allow carservice_app system_car_data_file:dir create_dir_perms;
allow carservice_app system_car_data_file:{ file lnk_file } create_file_perms;
+allow carservice_app cgroup:file rw_file_perms;
+
# For I/O stats tracker
allow carservice_app proc_uid_io_stats:file { read open getattr };
@@ -54,8 +59,5 @@
# To access /sys/fs/<type>/<partition>/lifetime_write_kbytes
allow carservice_app sysfs_fs_lifetime_write:file { getattr open read };
-# For allowing dumpstate to be called by CarBugreportManagerService only in userdebug or eng builds.
-userdebug_or_eng(`
set_prop(carservice_app, ctl_start_prop)
unix_socket_connect(carservice_app, dumpstate, dumpstate)
-')
\ No newline at end of file
diff --git a/car_product/sepolicy/private/dumpstate.te b/car_product/sepolicy/private/dumpstate.te
new file mode 100644
index 0000000..24a0208
--- /dev/null
+++ b/car_product/sepolicy/private/dumpstate.te
@@ -0,0 +1,3 @@
+set_prop(dumpstate, ctl_start_prop)
+set_prop(dumpstate, ctl_stop_prop)
+allow dumpstate dumpstate_socket:sock_file write;
\ No newline at end of file
diff --git a/car_product/sepolicy/private/file_contexts b/car_product/sepolicy/private/file_contexts
index b8f62fa..908c853 100644
--- a/car_product/sepolicy/private/file_contexts
+++ b/car_product/sepolicy/private/file_contexts
@@ -2,3 +2,7 @@
/data/system/car(/.*)? u:object_r:system_car_data_file:s0
+
+/system/bin/car-bugreportd u:object_r:dumpstate_exec:s0
+/dev/socket/car_br_progress_socket u:object_r:dumpstate_socket:s0
+/dev/socket/car_br_output_socket u:object_r:dumpstate_socket:s0
diff --git a/car_product/sepolicy/private/system_app.te b/car_product/sepolicy/private/system_app.te
new file mode 100644
index 0000000..232b117
--- /dev/null
+++ b/car_product/sepolicy/private/system_app.te
@@ -0,0 +1 @@
+hal_client_domain(system_app, hal_vehicle)
diff --git a/car_product/sepolicy/private/system_server.te b/car_product/sepolicy/private/system_server.te
index 44a11c5..2743021 100644
--- a/car_product/sepolicy/private/system_server.te
+++ b/car_product/sepolicy/private/system_server.te
@@ -1,3 +1,4 @@
# Car service in system server can read bootuser device id property
get_prop(system_server, car_bootuser_prop)
+allow system_server carservice_service:service_manager find;
diff --git a/evs/sepolicy/evs_app.te b/evs/sepolicy/evs_app.te
index b5e3c95..8c036b3 100644
--- a/evs/sepolicy/evs_app.te
+++ b/evs/sepolicy/evs_app.te
@@ -6,11 +6,11 @@
hal_client_domain(evs_app, hal_graphics_allocator)
# allow init to launch processes in this context
-type evs_app_exec, exec_type, file_type;
+type evs_app_exec, exec_type, file_type, system_file_type;
init_daemon_domain(evs_app)
# gets access to its own files on disk
-type evs_app_files, file_type;
+type evs_app_files, file_type, system_file_type;
allow evs_app evs_app_files:file { getattr open read };
allow evs_app evs_app_files:dir search;
diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index 3d5263e..f1f31e9 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -1,9 +1,10 @@
# evs_mock mock hardware driver service
type hal_evs_driver, domain, coredomain;
hal_server_domain(hal_evs_driver, hal_evs)
+hal_client_domain(hal_evs_driver, hal_evs)
# allow init to launch processes in this context
-type hal_evs_driver_exec, exec_type, file_type;
+type hal_evs_driver_exec, exec_type, file_type, system_file_type;
init_daemon_domain(hal_evs_driver)
binder_use(hal_evs_driver)
diff --git a/evs/sepolicy/evs_manager.te b/evs/sepolicy/evs_manager.te
index 58ea6aa..51acac1 100644
--- a/evs/sepolicy/evs_manager.te
+++ b/evs/sepolicy/evs_manager.te
@@ -2,10 +2,9 @@
type evs_manager, domain, coredomain;
hal_server_domain(evs_manager, hal_evs)
hal_client_domain(evs_manager, hal_evs)
-add_hwservice(hal_evs, hal_evs_hwservice)
# allow init to launch processes in this context
-type evs_manager_exec, exec_type, file_type;
+type evs_manager_exec, exec_type, file_type, system_file_type;
init_daemon_domain(evs_manager)
# allow use of hwservices
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index 3e50805..7d85445 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -496,6 +496,7 @@
<uses-permission android:name="android.permission.LOCATION_HARDWARE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
+ <uses-permission android:name="android.permission.READ_LOGS" />
<application android:label="@string/app_title"
android:directBootAware="true"
@@ -526,10 +527,10 @@
android:resource="@xml/car_trust_agent"/>
</service>
<activity android:name="com.android.car.pm.ActivityBlockingActivity"
+ android:documentLaunchMode="always"
android:excludeFromRecents="true"
- android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="false"
- android:launchMode="singleTask">
+ android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
diff --git a/service/proto/BLEHandshake.proto b/service/proto/BLEHandshake.proto
deleted file mode 100644
index 26f5783..0000000
--- a/service/proto/BLEHandshake.proto
+++ /dev/null
@@ -1,14 +0,0 @@
-syntax = "proto3";
-
-package com.android.car.trust.BLEHandshake;
-
-option java_package = "com.android.car.trust";
-option java_outer_classname = "BLEHandshake";
-
-message VersionExchange {
- // Required.
- int32 minSupportedVersion = 1;
-
- // Required.
- int32 maxSupportedVersion = 2;
-}
\ No newline at end of file
diff --git a/service/proto/BLEStream.proto b/service/proto/BLEStream.proto
deleted file mode 100644
index fe10cbd..0000000
--- a/service/proto/BLEStream.proto
+++ /dev/null
@@ -1,43 +0,0 @@
-syntax = "proto3";
-
-package com.android.car.trust.BLEStream;
-
-option java_package = "com.android.car.trust";
-option java_outer_classname = "BLEStream";
-
-// A message across a BLE channel.
-message BLEMessage {
- // The current version of the protocol.
- int32 version = 1;
-
- enum OperationType {
- // The contents of the payload are unknown.
- UNKNOWN = 0;
-
- // The payload contains handshake messages needed to set up encryption.
- ENCRYPTION_HANDSHAKE = 1;
-
- // The message is an acknowledgment of a previously received message. The
- // payload for this type should be empty.
- ACK = 2;
-
- // The payload contains a client-specific message.
- CLIENT_MESSAGE = 3;
- }
-
- // The operation that this message represents.
- OperationType operation = 2;
-
- // A 1-based packet number. The first message will have a value of "1" rather
- // than "0".
- fixed32 packet_number = 3;
-
- // The total number of packets in the message stream.
- fixed32 total_packets = 4;
-
- // Whether the payload field is encrypted.
- bool is_payload_encrypted = 5;
-
- // The bytes that represent the message content for this packet.
- bytes payload = 6;
-}
diff --git a/service/proto/ble_message.proto b/service/proto/ble_message.proto
new file mode 100644
index 0000000..c1610d7
--- /dev/null
+++ b/service/proto/ble_message.proto
@@ -0,0 +1,30 @@
+syntax = "proto3";
+
+package aae.blemessagestream;
+
+import "packages/services/Car/service/proto/operation_type.proto";
+
+option java_package = "com.android.car.BLEStreamProtos";
+option java_outer_classname = "BLEMessageProto";
+
+// A message across a BLE channel.
+message BLEMessage {
+ // The current version of the protocol.
+ int32 version = 1;
+
+ // The operation that this message represents.
+ OperationType operation = 2;
+
+ // A 1-based packet number. The first message will have a value of "1" rather
+ // than "0".
+ fixed32 packet_number = 3;
+
+ // The total number of packets in the message stream.
+ fixed32 total_packets = 4;
+
+ // Whether the payload field is encrypted.
+ bool is_payload_encrypted = 5;
+
+ // The bytes that represent the message content for this packet.
+ bytes payload = 6;
+}
diff --git a/service/proto/ble_version_exchange.proto b/service/proto/ble_version_exchange.proto
new file mode 100644
index 0000000..28ef351
--- /dev/null
+++ b/service/proto/ble_version_exchange.proto
@@ -0,0 +1,21 @@
+syntax = "proto3";
+
+package aae.blemessagestream;
+
+option java_package = "com.android.car.BLEStreamProtos";
+option java_outer_classname = "VersionExchangeProto";
+
+message BLEVersionExchange {
+ // Minimum supported protobuf version.
+ int32 minSupportedMessagingVersion = 1;
+
+ // Maximum supported protobuf version.
+ int32 maxSupportedMessagingVersion = 2;
+
+ // Minimum supported version of the encryption engine.
+ int32 minSupportedSecurityVersion = 3;
+
+ // Maximum supported version of the encryption engine.
+ int32 maxSupportedSecurityVersion = 4;
+
+}
diff --git a/service/proto/jarjar-rules.txt b/service/proto/jarjar-rules.txt
index c06c995..d27aecb 100644
--- a/service/proto/jarjar-rules.txt
+++ b/service/proto/jarjar-rules.txt
@@ -1 +1 @@
-rule com.google.protobuf.** com.android.car.trust.protobuf.@1
\ No newline at end of file
+rule com.google.protobuf.** com.android.car.protobuf.@1
diff --git a/service/proto/operation_type.proto b/service/proto/operation_type.proto
new file mode 100644
index 0000000..cce9f70
--- /dev/null
+++ b/service/proto/operation_type.proto
@@ -0,0 +1,28 @@
+syntax = "proto3";
+
+package aae.blemessagestream;
+
+option java_package = "com.android.car.BLEStreamProtos";
+option java_outer_classname = "BLEOperationProto";
+
+// The different message types that indicate the content of the payload.
+//
+// Ensure that these values are positive to reduce incurring too many bytes
+// to encode.
+enum OperationType {
+ // The contents of the payload are unknown.
+ //
+ // Note, this enum name is prefixed. See
+ // go/proto-best-practices-checkers#enum-default-value-name-conflict
+ OPERATION_TYPE_UNKNOWN = 0;
+
+ // The payload contains handshake messages needed to set up encryption.
+ ENCRYPTION_HANDSHAKE = 2;
+
+ // The message is an acknowledgment of a previously received message. The
+ // payload for this type should be empty.
+ ACK = 3;
+
+ // The payload contains a client-specific message.
+ CLIENT_MESSAGE = 4;
+}
diff --git a/service/proto/phone_auth.proto b/service/proto/phone_auth.proto
new file mode 100644
index 0000000..4465a55
--- /dev/null
+++ b/service/proto/phone_auth.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+
+package aae.trustagent;
+
+option java_package = "com.android.car.trust";
+option java_outer_classname = "PhoneAuthProto";
+
+message PhoneCredentials {
+ // Required field representing the escrow token that needs to be sent for authenticating the user
+ fixed64 escrow_token = 1;
+
+ // Required field representing the handle associated with the escrow token that needs to be sent
+ // for authenticating the user
+ fixed64 handle = 2;
+}
\ No newline at end of file
diff --git a/service/res/values-af/config.xml b/service/res/values-af/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-af/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-af/strings.xml b/service/res/values-af/strings.xml
index d5b6dbd..8da32cf 100644
--- a/service/res/values-af/strings.xml
+++ b/service/res/values-af/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Vir jou veiligheid is dié aktiwiteit nie beskikbaar terwyl jy bestuur nie.\nWag totdat jy geparkeer het om voort te gaan."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Kies <xliff:g id="EXIT_BUTTON">%s</xliff:g> om oor te begin met veilige programkenmerke."</string>
<string name="exit_button" msgid="5829638404777671253">"Terug"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Ontfoutin."</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lees diagnostiese data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lees diagnostiese data van die motor af."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"vee diagnostiese data uit"</string>
diff --git a/service/res/values-am/config.xml b/service/res/values-am/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-am/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-am/strings.xml b/service/res/values-am/strings.xml
index 3b5594c..41b7622 100644
--- a/service/res/values-am/strings.xml
+++ b/service/res/values-am/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"ለእርስዎ ደህንነት ሲባል፣ ይህ እንቅስቃሴ እርስዎ በሚነዱበት ጊዜ አይገኝም። \nለመቀጠል እንዲችሉ፣ መኪናዎ እስከሚቆም ድረስ ይጠብቁ።"</string>
<string name="exit_button_message" msgid="8554690915924055685">"ከደህንነት አስተማማኝ የሆኑ የመተግበሪያ ባህሪያት ጋር መልሶ ለመጀመር፣ <xliff:g id="EXIT_BUTTON">%s</xliff:g>ን ይምረጡ።"</string>
<string name="exit_button" msgid="5829638404777671253">"ተመለስ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"የአርም መረጃ"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"የምርመራ ውሂብን አንብብ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ከመኪናው ላይ የምርመራ ውሂብን ያንብቡ።"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"የምርመራ ውሂብን አጽዳ"</string>
diff --git a/service/res/values-ar/config.xml b/service/res/values-ar/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ar/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ar/strings.xml b/service/res/values-ar/strings.xml
index 288e0bb..d9b7040 100644
--- a/service/res/values-ar/strings.xml
+++ b/service/res/values-ar/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"حرصًا على سلامتك، لا يتوفّر هذا النشاط أثناء القيادة.\nللمتابعة، يمكنك الانتظار حتى تتوقّف السيارة."</string>
<string name="exit_button_message" msgid="8554690915924055685">"للبدء من جديد باستخدام ميزات تطبيق آمنة، اختَر <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"رجوع"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"التصحيح"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"قراءة البيانات التشخيصية"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"يمكنك قراءة البيانات التشخيصية من السيارة."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"محو البيانات التشخيصية"</string>
diff --git a/service/res/values-as/config.xml b/service/res/values-as/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-as/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-as/strings.xml b/service/res/values-as/strings.xml
index d40ec8f..0cac303 100644
--- a/service/res/values-as/strings.xml
+++ b/service/res/values-as/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"আপোনাৰ নিৰাপত্তাৰ বাবে এই কাৰ্যকলাপটো গাড়ী চলাই থকা সময়ত কৰিব নোৱাৰি।\nগাড়ীখন পাৰ্ক কৰি কামটো কৰক।"</string>
<string name="exit_button_message" msgid="8554690915924055685">"সুৰক্ষিত এপ্ সুবিধাসহ আকৌ আৰম্ভ কৰিবলৈ <xliff:g id="EXIT_BUTTON">%s</xliff:g> বাছনি কৰক।"</string>
<string name="exit_button" msgid="5829638404777671253">"উভতি যাওক"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ডিবাগ তথ্য"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ডায়গন’ষ্টিক ডেটা পঢ়িব"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"গাড়ীৰ ডায়গ’ষ্টিক তথ্য পঢ়িব।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ডায়গন’ষ্টিক ডেটা মচিব"</string>
diff --git a/service/res/values-az/config.xml b/service/res/values-az/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-az/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-az/strings.xml b/service/res/values-az/strings.xml
index 50f8279..5cdfa3d 100644
--- a/service/res/values-az/strings.xml
+++ b/service/res/values-az/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Təhlükəsizliyiniz üçün bu əməliyyat sürüş zamanı əlçatan deyil.\nDavam etmək üçün park edənədək gözləyin."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Təhlükəsiz tətbiq xüsusiyyətləri ilə başlamaq üçün <xliff:g id="EXIT_BUTTON">%s</xliff:g> seçin."</string>
<string name="exit_button" msgid="5829638404777671253">"Geri"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debaq məlumatı"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"diaqnoztika məlumatlarını oxumaq"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Avtomobilin diaqnoztika məlumatlarını oxumaq."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"diaqnoztika məlumatlarını silmək"</string>
diff --git a/service/res/values-b+sr+Latn/config.xml b/service/res/values-b+sr+Latn/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-b+sr+Latn/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-b+sr+Latn/strings.xml b/service/res/values-b+sr+Latn/strings.xml
index 1f23ce7..e0da81d 100644
--- a/service/res/values-b+sr+Latn/strings.xml
+++ b/service/res/values-b+sr+Latn/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Ova aktivnost nije dostupna dok vozite radi vaše bezbednosti.\nDa biste nastavili, prvo se parkirajte."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Da biste ponovo počeli sa bezbednim funkcijama aplikacije, izaberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Nazad"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"čitanje dijagnostičkih podataka"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Čitanje dijagnostičkih podataka iz automobila."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"brisanje dijagnostičkih podataka"</string>
diff --git a/service/res/values-be/config.xml b/service/res/values-be/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-be/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-be/strings.xml b/service/res/values-be/strings.xml
index 6174588..b5d46ae 100644
--- a/service/res/values-be/strings.xml
+++ b/service/res/values-be/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Дзеля вашай бяспекі гэта дзеянне недаступнае, калі вы за рулём.\nСпачатку прыпаркуйцеся."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Каб перазапусціць праграму ў бяспечным рэжыме, націсніце кнопку \"<xliff:g id="EXIT_BUTTON">%s</xliff:g>\"."</string>
<string name="exit_button" msgid="5829638404777671253">"Назад"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"атрымліваць даныя дыягностыкі"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Счытванне дыягнастычных даных аўтамабіля"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ачысціць даныя дыягностыкі"</string>
diff --git a/service/res/values-bg/config.xml b/service/res/values-bg/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-bg/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-bg/strings.xml b/service/res/values-bg/strings.xml
index fd36d20..d5c1fa4 100644
--- a/service/res/values-bg/strings.xml
+++ b/service/res/values-bg/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"От съображения за безопасност тази функция не е достъпна при шофиране.\nЗа да продължите, трябва първо да паркирате."</string>
<string name="exit_button_message" msgid="8554690915924055685">"За да рестартирате приложението и безопасните му функции, изберете „<xliff:g id="EXIT_BUTTON">%s</xliff:g>“."</string>
<string name="exit_button" msgid="5829638404777671253">"Назад"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"четене на диагностични данни"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Четене на диагностични данни от автомобила."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"изчистване на диагностичните данни"</string>
diff --git a/service/res/values-bn/config.xml b/service/res/values-bn/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-bn/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-bn/strings.xml b/service/res/values-bn/strings.xml
index 0b03a73..3b5957b 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"আপনার সুরক্ষার জন্য, ড্রাইভ করার সময় এটি করা যাবে না।\nচালিয়ে যেতে, গাড়ি পার্ক করা পর্যন্ত অপেক্ষা করুন।"</string>
<string name="exit_button_message" msgid="8554690915924055685">"অ্যাপের সুরক্ষিত ফিচারগুলি নিয়ে আবার শুরু করতে, <xliff:g id="EXIT_BUTTON">%s</xliff:g> বেছে নিন।"</string>
<string name="exit_button" msgid="5829638404777671253">"আবার চালু করুন"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ডিবাগ তথ্য"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ডায়াগনস্টিক ডেটা দেখা"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"গাড়ির ডায়াগনস্টিক সংক্রান্ত ডেটা দেখা।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ডায়াগনস্টিকস ডেটা সরানো"</string>
diff --git a/service/res/values-bs/config.xml b/service/res/values-bs/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-bs/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-bs/strings.xml b/service/res/values-bs/strings.xml
index 2d69ac0..5770adf 100644
--- a/service/res/values-bs/strings.xml
+++ b/service/res/values-bs/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Radi vaše sigurnosti, ova aktivnost nije dostupna tokom vožnje.\nDa nastavite, sačekajte da se zaustavite."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Da počnete ponovo s funkcijama sigurne aplikacije, odaberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Nazad"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"očitati dijagnostičke podatke"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Očitati dijagnostičke podatke automobila."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"brisati dijagnostičke podatke"</string>
diff --git a/service/res/values-ca/config.xml b/service/res/values-ca/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ca/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ca/strings.xml b/service/res/values-ca/strings.xml
index e31da04..535b403 100644
--- a/service/res/values-ca/strings.xml
+++ b/service/res/values-ca/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Per motius de seguretat, aquesta activitat no està disponible mentre condueixes.\nPer continuar, has d\'estar aparcat."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Per tornar a començar amb unes funcions d\'aplicació segures, selecciona <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Enrere"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Depuració"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"llegeix les dades de diagnòstic"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Llegeix les dades de diagnòstic del cotxe."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"esborra les dades de diagnòstic"</string>
diff --git a/service/res/values-cs/config.xml b/service/res/values-cs/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-cs/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-cs/strings.xml b/service/res/values-cs/strings.xml
index b01f87b..369cdbc 100644
--- a/service/res/values-cs/strings.xml
+++ b/service/res/values-cs/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Tato aktivita není při řízení z bezpečnostních důvodů dostupná.\nPokračovat můžete, až zaparkujete."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Chcete-li začít znovu s bezpečnými funkcemi aplikace, vyberte <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Zpět"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"čtení diagnostických dat"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Čtení diagnostických dat z auta."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"vymazat diagnostická data"</string>
diff --git a/service/res/values-da/config.xml b/service/res/values-da/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-da/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-da/strings.xml b/service/res/values-da/strings.xml
index d3a3fb0..5513137 100644
--- a/service/res/values-da/strings.xml
+++ b/service/res/values-da/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Af hensyn til din sikkerhed kan du ikke få adgang til denne aktivitet, mens du kører.\nParkér, før du kan fortsætte."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Vælg <xliff:g id="EXIT_BUTTON">%s</xliff:g> for at starte forfra med sikre appfunktioner."</string>
<string name="exit_button" msgid="5829638404777671253">"Tilbage"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"tjekke diagnosticeringsdata"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Tjek diagnosticeringsdata fra bilen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"rydde diagnosticeringsdata"</string>
diff --git a/service/res/values-de/config.xml b/service/res/values-de/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-de/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-de/strings.xml b/service/res/values-de/strings.xml
index 04c3af6..ff4c461 100644
--- a/service/res/values-de/strings.xml
+++ b/service/res/values-de/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Aus Sicherheitsgründen ist diese Aktivität während der Fahrt nicht verfügbar.\nWarte, bis das Fahrzeug geparkt ist."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Wähle <xliff:g id="EXIT_BUTTON">%s</xliff:g>, um die App mit sicheren Funktionen neu zu starten."</string>
<string name="exit_button" msgid="5829638404777671253">"Zurück"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"Diagnosedaten zu lesen"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Diagnosedaten des Autos lesen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Diagnosedaten zu löschen"</string>
diff --git a/service/res/values-el/config.xml b/service/res/values-el/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-el/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-el/strings.xml b/service/res/values-el/strings.xml
index ec05dc2..d2846d8 100644
--- a/service/res/values-el/strings.xml
+++ b/service/res/values-el/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Για λόγους ασφαλείας, η δραστηρ. δεν είναι διαθέσιμη όταν οδηγείτε.\nΓια να συνεχίσετε, περιμένετε μέχρι να σταθμεύσετε."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Για να ξεκινήσετε από την αρχή με ασφαλείς λειτουργίες εφαρμογής, επιλέξτε <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Πίσω"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Πλ. εντ. σφ."</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"παρακολούθηση δεδομένων διαγνωστικών στοιχείων"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Παρακολούθηση δεδομένων διαγνωστικών στοιχείων από το αυτοκίνητο."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"διαγραφή δεδομένων διαγνωστικών στοιχείων"</string>
diff --git a/service/res/values-en-rAU/config.xml b/service/res/values-en-rAU/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-en-rAU/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-rAU/strings.xml b/service/res/values-en-rAU/strings.xml
index d102771..49741f1 100644
--- a/service/res/values-en-rAU/strings.xml
+++ b/service/res/values-en-rAU/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"For your safety, this activity isn’t available while driving.\nTo continue, wait until you’ve parked."</string>
<string name="exit_button_message" msgid="8554690915924055685">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Back"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
diff --git a/service/res/values-en-rCA/config.xml b/service/res/values-en-rCA/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-en-rCA/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-rCA/strings.xml b/service/res/values-en-rCA/strings.xml
index d102771..49741f1 100644
--- a/service/res/values-en-rCA/strings.xml
+++ b/service/res/values-en-rCA/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"For your safety, this activity isn’t available while driving.\nTo continue, wait until you’ve parked."</string>
<string name="exit_button_message" msgid="8554690915924055685">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Back"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
diff --git a/service/res/values-en-rGB/config.xml b/service/res/values-en-rGB/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-en-rGB/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-rGB/strings.xml b/service/res/values-en-rGB/strings.xml
index d102771..49741f1 100644
--- a/service/res/values-en-rGB/strings.xml
+++ b/service/res/values-en-rGB/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"For your safety, this activity isn’t available while driving.\nTo continue, wait until you’ve parked."</string>
<string name="exit_button_message" msgid="8554690915924055685">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Back"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
diff --git a/service/res/values-en-rIN/config.xml b/service/res/values-en-rIN/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-en-rIN/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-rIN/strings.xml b/service/res/values-en-rIN/strings.xml
index d102771..49741f1 100644
--- a/service/res/values-en-rIN/strings.xml
+++ b/service/res/values-en-rIN/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"For your safety, this activity isn’t available while driving.\nTo continue, wait until you’ve parked."</string>
<string name="exit_button_message" msgid="8554690915924055685">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Back"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
diff --git a/service/res/values-en-rXC/config.xml b/service/res/values-en-rXC/config.xml
deleted file mode 100644
index a19ba0f..0000000
--- a/service/res/values-en-rXC/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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
index fbe2ce1..5bbe05b 100644
--- a/service/res/values-en-rXC/strings.xml
+++ b/service/res/values-en-rXC/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"For your safety, this activity isn’t available while driving.\nTo continue, wait until you’re parked."</string>
<string name="exit_button_message" msgid="8554690915924055685">"To start over with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Back"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
diff --git a/service/res/values-es-rUS/config.xml b/service/res/values-es-rUS/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-es-rUS/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-es-rUS/strings.xml b/service/res/values-es-rUS/strings.xml
index 9011028..ebcc08c 100644
--- a/service/res/values-es-rUS/strings.xml
+++ b/service/res/values-es-rUS/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Por razones de seguridad, esta actividad no está disponible al conducir.\nPara continuar espera hasta que estaciones."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Para volver a comenzar con funciones de app seguras, selecciona <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Atrás"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Depuración"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"leer datos de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Leer datos de diagnóstico del vehículo."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"borrar datos de diagnóstico"</string>
diff --git a/service/res/values-es/config.xml b/service/res/values-es/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-es/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-es/strings.xml b/service/res/values-es/strings.xml
index 5d54e80..e2a9e88 100644
--- a/service/res/values-es/strings.xml
+++ b/service/res/values-es/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Por tu seguridad, esta actividad no está disponible mientras conduces.\nPuedes continuar cuando hayas aparcado."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Para volver a empezar con funciones de aplicaciones seguras, selecciona <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Atrás"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Depuración"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"consultar datos de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Consultar los datos de diagnóstico del coche."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"borrar los datos de diagnóstico"</string>
diff --git a/service/res/values-et/config.xml b/service/res/values-et/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-et/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-et/strings.xml b/service/res/values-et/strings.xml
index e0b6f86..cfaf748 100644
--- a/service/res/values-et/strings.xml
+++ b/service/res/values-et/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Teie turvalisuse tõttu ei ole see toiming sõitmise ajal saadaval.\nJätkamiseks oodake, kuni olete parkinud."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Uuesti alustamiseks turvaliste rakenduste funktsioonidega valige <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Tagasi"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Sil.-teave"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"diagnostikaandmete lugemine"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Auto diagnostikaandmete lugemine."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"diagnostikaandmete kustutamine"</string>
diff --git a/service/res/values-eu/config.xml b/service/res/values-eu/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-eu/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-eu/strings.xml b/service/res/values-eu/strings.xml
index 5f0249a..9e031a5 100644
--- a/service/res/values-eu/strings.xml
+++ b/service/res/values-eu/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Zure segurtasuna bermatzeko, eginbide hau ezin da erabili gidatu bitartean.\nAurrera egiteko, itxaron autoa aparkatu arte."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Berriro hasi nahi baduzu aplikazioaren eginbide seguruekin, hautatu <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Atzera"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"irakurri datu diagnostikoak"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Irakurri autoaren datu diagnostikoak."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"garbitu datu diagnostikoak"</string>
diff --git a/service/res/values-fa/config.xml b/service/res/values-fa/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-fa/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-fa/strings.xml b/service/res/values-fa/strings.xml
index 60c38d9..2e29029 100644
--- a/service/res/values-fa/strings.xml
+++ b/service/res/values-fa/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"بنا به دلایل ایمنی، این فعالیت درحین رانندگی دردسترس نیست.\n برای ادامه، تا زمان توقف خودرو صبر کنید."</string>
<string name="exit_button_message" msgid="8554690915924055685">"برای شروع مجدد با ویژگیهای برنامه امن، <xliff:g id="EXIT_BUTTON">%s</xliff:g> را انتخاب کنید."</string>
<string name="exit_button" msgid="5829638404777671253">"برگشت"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"اطلاعات اشکالزدایی"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"خواندن دادههای عیبیابی"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"دادههای عیبیابی خودرو را بخوانید."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"پاک کردن دادههای عیبیابی"</string>
diff --git a/service/res/values-fi/config.xml b/service/res/values-fi/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-fi/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-fi/strings.xml b/service/res/values-fi/strings.xml
index 88d4188..256cdfa 100644
--- a/service/res/values-fi/strings.xml
+++ b/service/res/values-fi/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Turvallisuussyistä toiminto ei ole käytettävissä ajon aikana.\nVoit jatkaa, kun olet pysäköinyt auton."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Jos haluat aloittaa alusta turvallisilla sovellusominaisuuksilla, valitse <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Takaisin"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"nähdä diagnostiikkadataa"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"lukea auton diagnostiikkadataa"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"poistaa diagnostiikkatiedot"</string>
diff --git a/service/res/values-fr-rCA/config.xml b/service/res/values-fr-rCA/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-fr-rCA/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-fr-rCA/strings.xml b/service/res/values-fr-rCA/strings.xml
index 82dc2e6..470879d 100644
--- a/service/res/values-fr-rCA/strings.xml
+++ b/service/res/values-fr-rCA/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Pour votre sécurité, cette activité est bloquée lorsque vous conduisez.\nVous devez être stationné pour continuer."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Pour recommencer avec des fonctionnalités d\'application sécurisées, sélectionnez <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Retour"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Info débog"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lire des données de diagnostic"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lire des données de diagnostic à partir de la voiture."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"effacer les données de diagnostic"</string>
diff --git a/service/res/values-fr/config.xml b/service/res/values-fr/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-fr/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-fr/strings.xml b/service/res/values-fr/strings.xml
index 4c742e3..6d562be 100644
--- a/service/res/values-fr/strings.xml
+++ b/service/res/values-fr/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Pour votre sécurité, cette activité n\'est pas disponible pendant la conduite.\nPour continuer, attendez d\'être garé."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Pour recommencer avec des fonctionnalités d\'application sécurisées, sélectionnez <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Retour"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"Lire les données de diagnostic"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lire les données de diagnostic de la voiture."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Effacer les données de diagnostic"</string>
diff --git a/service/res/values-gl/config.xml b/service/res/values-gl/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-gl/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-gl/strings.xml b/service/res/values-gl/strings.xml
index f3b1a83..efcf7b2 100644
--- a/service/res/values-gl/strings.xml
+++ b/service/res/values-gl/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Pola túa seguranza, esta actividade non está dispoñible mentres conduces.\nPodes continuar cando aparques."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Para comezar de novo coas funcións de aplicacións seguras, selecciona o botón <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Atrás"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Info. dep."</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ler datos de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Ler datos de diagnóstico do coche."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"borrar datos de diagnóstico"</string>
diff --git a/service/res/values-gu/config.xml b/service/res/values-gu/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-gu/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-gu/strings.xml b/service/res/values-gu/strings.xml
index e465258..7c00a7d 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"તમારી સલામતી માટે કાર ચલાવતી વખતે આ પ્રવૃત્તિ ઉપલબ્ધ નથી.\nચાલુ રાખવા માટે કાર પાર્ક થવા સુધી રાહ જુઓ."</string>
<string name="exit_button_message" msgid="8554690915924055685">"સુરક્ષિત ઍપ્લિકેશન સુવિધાઓ સાથે ફરી શરૂ કરવા, <xliff:g id="EXIT_BUTTON">%s</xliff:g> પસંદ કરો."</string>
<string name="exit_button" msgid="5829638404777671253">"પાછળ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ડિબગમાહિતી"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"નિદાનનો ડેટા વાંચો"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"કારમાંથી નિદાનનો ડેટા વાંચો."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"નિદાનનો ડેટા સાફ કરો"</string>
diff --git a/service/res/values-hi/config.xml b/service/res/values-hi/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-hi/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-hi/strings.xml b/service/res/values-hi/strings.xml
index a53a9ce..ff8429a 100644
--- a/service/res/values-hi/strings.xml
+++ b/service/res/values-hi/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"आपकी सुरक्षा के लिए, गाड़ी चलाते समय यह गतिविधि मौजूद नहीं रहती है.\nजारी रखने के लिए गाड़ी पार्क करनी होगी."</string>
<string name="exit_button_message" msgid="8554690915924055685">"सुरक्षित ऐप्लिकेशन सुविधाएं फिर से शुरू करने के लिए, <xliff:g id="EXIT_BUTTON">%s</xliff:g> चुनें."</string>
<string name="exit_button" msgid="5829638404777671253">"वापस शुरू करें"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"गड़बड़ी की पहचान का डेटा देख सकता है"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"कार की \'गड़बड़ी की पहचान का डेटा\' देख सकता है."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"गड़बड़ी की पहचान का डेटा मिटा सकता है"</string>
diff --git a/service/res/values-hr/config.xml b/service/res/values-hr/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-hr/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-hr/strings.xml b/service/res/values-hr/strings.xml
index edc2b17..2d2060b 100644
--- a/service/res/values-hr/strings.xml
+++ b/service/res/values-hr/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Radi vaše sigurnosti ta aktivnost nije dostupna tijekom vožnje.\nDa biste nastavili, pričekajte dok se ne zaustavite."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Da biste započeli ponovo sa sigurnim značajkama aplikacije, odaberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Natrag"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Inf. o otkl. pogrešaka"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"čitati dijagnostičke podatke"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"čitati dijagnostičke podatke automobila"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"izbrisati dijagnostičke podatke"</string>
diff --git a/service/res/values-hu/config.xml b/service/res/values-hu/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-hu/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-hu/strings.xml b/service/res/values-hu/strings.xml
index ef60a68..f427b07 100644
--- a/service/res/values-hu/strings.xml
+++ b/service/res/values-hu/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Az Ön biztonsága érdekében ez a tevékenység nem végezhető vezetés közben.\nLeparkolás után folytathatja a tevékenységet."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Ha biztonságos alkalmazásfunkciókkal szeretné újrakezdeni, válassza a következő gombot: <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Vissza"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Hibakeresési adatok"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"olvashatja a diagnosztikai adatokat"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Olvashatja az autó diagnosztikai adatait."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"törölheti a diagnosztikai adatokat"</string>
diff --git a/service/res/values-hy/config.xml b/service/res/values-hy/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-hy/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-hy/strings.xml b/service/res/values-hy/strings.xml
index 34ae170..a706dc4 100644
--- a/service/res/values-hy/strings.xml
+++ b/service/res/values-hy/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Անվտանգության նկատառումներով այս գործողությունը հասանելի չէ վարելու ռեժիմում:\nՇարունակելու համար կայանեք մեքենան:"</string>
<string name="exit_button_message" msgid="8554690915924055685">"Հավելվածն անվտանգ ռեժիմում վերագործարկելու համար սեղմեք<xliff:g id="EXIT_BUTTON">%s</xliff:g> կոճակը:"</string>
<string name="exit_button" msgid="5829638404777671253">"Հետ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"կարդալ ախտորոշման մասին տվյալները"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Կարդալ մեքենայի ախտորոշման տվյալները։"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"մաքրել ախտորոշման տվյալները"</string>
diff --git a/service/res/values-in/config.xml b/service/res/values-in/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-in/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-in/strings.xml b/service/res/values-in/strings.xml
index 169cdcc..3651eaa 100644
--- a/service/res/values-in/strings.xml
+++ b/service/res/values-in/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Demi keamanan Anda, aktivitas ini tidak tersedia saat Anda mengemudi.\nUntuk melanjutkan, tunggu hingga mobil terparkir."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Untuk mulai dari awal dengan fitur apl yang aman, pilih <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Kembali"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Info Debug"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"membaca data diagnostik"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Membaca data diagnostik dari mobil."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"menghapus data diagnostik"</string>
diff --git a/service/res/values-is/config.xml b/service/res/values-is/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-is/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-is/strings.xml b/service/res/values-is/strings.xml
index bd81b4c..64f68f5 100644
--- a/service/res/values-is/strings.xml
+++ b/service/res/values-is/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Af öryggisástæðum er þessi aðgerð ekki í boði við akstur.\nLeggðu ökutækinu áður en þú heldur áfram."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Til að byrja aftur að setja upp örugga forritseiginleika skaltu velja <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Til baka"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Villuleit"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lesa greiningargögn"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lesa greiningargögn úr bílnum."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"hreinsa greiningargögn"</string>
diff --git a/service/res/values-it/config.xml b/service/res/values-it/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-it/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-it/strings.xml b/service/res/values-it/strings.xml
index f6be2f8..07aad4e 100644
--- a/service/res/values-it/strings.xml
+++ b/service/res/values-it/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Per motivi di sicurezza, questa attività non è disponibile durante la guida.\nPotrai continuare quando avrai parcheggiato."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Seleziona <xliff:g id="EXIT_BUTTON">%s</xliff:g> per ricominciare con le funzionalità sicure dell\'app."</string>
<string name="exit_button" msgid="5829638404777671253">"Indietro"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Info debug"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"Lettura dei dati diagnostici"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Consente di leggere i dati diagnostici dell\'automobile."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Cancellazione dei dati diagnostici"</string>
diff --git a/service/res/values-iw/config.xml b/service/res/values-iw/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-iw/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-iw/strings.xml b/service/res/values-iw/strings.xml
index 7e28b02..1770cf9 100644
--- a/service/res/values-iw/strings.xml
+++ b/service/res/values-iw/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"מטעמי בטיחות, פעילות זו אינה זמינה בזמן נהיגה.\nכדי להמשיך, צריך להמתין עד לחניית הרכב."</string>
<string name="exit_button_message" msgid="8554690915924055685">"כדי להפעיל מחדש את האפליקציה במצב בטוח, יש ללחוץ על <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"הקודם"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"קריאת נתוני אבחון"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"קריאת נתוני אבחון מהרכב."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"מחיקת נתוני האבחון"</string>
diff --git a/service/res/values-ja/config.xml b/service/res/values-ja/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ja/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ja/strings.xml b/service/res/values-ja/strings.xml
index 22ca04f..9c8ad93 100644
--- a/service/res/values-ja/strings.xml
+++ b/service/res/values-ja/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"安全上の理由により、運転中はこのアクティビティをご利用いただけません。\n続行するには駐車してください。"</string>
<string name="exit_button_message" msgid="8554690915924055685">"アプリをセーフモードで再起動するには、<xliff:g id="EXIT_BUTTON">%s</xliff:g> を選択します。"</string>
<string name="exit_button" msgid="5829638404777671253">"戻る"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"デバッグ情報"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"診断データの読み取り"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"車から診断データを読み取ります。"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"診断データの消去"</string>
diff --git a/service/res/values-ka/config.xml b/service/res/values-ka/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ka/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ka/strings.xml b/service/res/values-ka/strings.xml
index bf533b3..d8343a8 100644
--- a/service/res/values-ka/strings.xml
+++ b/service/res/values-ka/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"ეს აქტივობა მიუწვდომელია მანქანის მართვისას, უსაფრთხოების მოსაზრებებიდან გამომდინარე.\nგთხოვთ, ჯერ გააჩეროთ მანქანა."</string>
<string name="exit_button_message" msgid="8554690915924055685">"აპის უსაფრთხო რეჟიმში გასაშვებად აირჩიეთ „<xliff:g id="EXIT_BUTTON">%s</xliff:g>“."</string>
<string name="exit_button" msgid="5829638404777671253">"უკან"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"გამართვის ინფორმაცია"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"დიაგნოსტიკური მონაცემების წაკითხვა"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"დიაგნოსტიკური მონაცემების წაკითხვა მანქანიდან."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"დიაგნოსტიკური მონაცემების გასუფთავება"</string>
diff --git a/service/res/values-kk/config.xml b/service/res/values-kk/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-kk/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-kk/strings.xml b/service/res/values-kk/strings.xml
index 2eeb9cf..b031e9d 100644
--- a/service/res/values-kk/strings.xml
+++ b/service/res/values-kk/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Көлік жүргізгенде, қауіпсіздік мақсатында бұл әрекетті орындау мүмкін емес.\nЖалғастыру үшін көлікті тұраққа қойыңыз."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Қолданбаны қауіпсіз күйде қайта іске қосу үшін <xliff:g id="EXIT_BUTTON">%s</xliff:g> түймесін басыңыз."</string>
<string name="exit_button" msgid="5829638404777671253">"Артқа"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Түзету"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"диагностикалық деректерді көру"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Көліктің диагностикалық деректерін көру."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"диагностикалық деректерді өшіру"</string>
diff --git a/service/res/values-km/config.xml b/service/res/values-km/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-km/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-km/strings.xml b/service/res/values-km/strings.xml
index d25d5aa..3039b03 100644
--- a/service/res/values-km/strings.xml
+++ b/service/res/values-km/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"ដើម្បីសុវត្ថិភាពរបស់អ្នក សកម្មភាពនេះមិនអាចប្រើបានទេ ពេលកំពុងបើកបរ។\nដើម្បីបន្ត សូមរង់ចាំរហូតទាល់តែអ្នកចតរថយន្តរួច។"</string>
<string name="exit_button_message" msgid="8554690915924055685">"ដើម្បីចាប់ផ្តើមឡើងវិញដោយប្រើមុខងារកម្មវិធីដែលមានសុវត្ថិភាព សូមជ្រើសរើស <xliff:g id="EXIT_BUTTON">%s</xliff:g> ។"</string>
<string name="exit_button" msgid="5829638404777671253">"ថយក្រោយ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ព័ត៌មានជួសជុល"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"អានទិន្នន័យវិភាគ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"អានអំពីទិន្នន័យវិភាគពីរថយន្ត។"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"សម្អាតទិន្នន័យវិភាគ"</string>
diff --git a/service/res/values-kn/config.xml b/service/res/values-kn/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-kn/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-kn/strings.xml b/service/res/values-kn/strings.xml
index 14b7b54..0473b2d 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"ನಿಮ್ಮ ಸುರಕ್ಷೆಗಾಗಿ, ಈ ಚಟುವಟಿಕೆಯು ವಾಹನ ಚಲಾಯಿಸುತ್ತಿರುವಾಗ ಲಭ್ಯವಿಲ್ಲ. ಮುಂದುವರೆಯಲು \n ಮಾಡಿ, ನೀವು ಪಾರ್ಕ್ ಮಾಡುವ ತನಕ ಕಾಯಿರಿ."</string>
<string name="exit_button_message" msgid="8554690915924055685">"ಆಪ್ನ ಸುರಕ್ಷೆ ಗುಣಲಕ್ಷಣಗಳನ್ನು ಒಳಗೊಂಡು ಮತ್ತೆ ಪ್ರಾರಂಭಿಸಲು, <xliff:g id="EXIT_BUTTON">%s</xliff:g> ಆಯ್ಕೆ ಮಾಡಿ."</string>
<string name="exit_button" msgid="5829638404777671253">"ಹಿಂದಕ್ಕೆ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ಡೀಬಗ್ ಮಾಹಿ"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ಡಯಾಗ್ನೋಸ್ಟಿಕ್ ಡೇಟಾವನ್ನು ಓದಿ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ಕಾರಿನಲ್ಲಿರುವ ಅದರ ಡಯಾಗ್ನೋಸ್ಟಿಕ್ ಡೇಟಾವನ್ನು ಓದಿ."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ಡಯಾಗ್ನೋಸ್ಟಿಕ್ ಡೇಟಾವನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
diff --git a/service/res/values-ko/config.xml b/service/res/values-ko/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ko/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ko/strings.xml b/service/res/values-ko/strings.xml
index cfcc030..4853d47 100644
--- a/service/res/values-ko/strings.xml
+++ b/service/res/values-ko/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"안전을 위해 운전 중에는 이용할 수 없는 활동입니다.\n계속하려면 먼저 주차하세요."</string>
<string name="exit_button_message" msgid="8554690915924055685">"안전한 앱 기능으로 다시 시작하려면 <xliff:g id="EXIT_BUTTON">%s</xliff:g>을(를) 선택하세요."</string>
<string name="exit_button" msgid="5829638404777671253">"뒤로"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"디버그 정보"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"진단 데이터 읽기"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"차량의 진단 데이터를 읽습니다."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"진단 데이터 삭제"</string>
diff --git a/service/res/values-ky/config.xml b/service/res/values-ky/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ky/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ky/strings.xml b/service/res/values-ky/strings.xml
index 2999b31..f2a21df 100644
--- a/service/res/values-ky/strings.xml
+++ b/service/res/values-ky/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Коопсуздугуңузду коргоо максатында, бул иш-аракетти унаа айдап баратканда аткарууга болбойт.\nТоктоп туруп, улантыңыз."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Колдонмонун коопсуз функцияларын иштетүү үчүн <xliff:g id="EXIT_BUTTON">%s</xliff:g> баскычын басыңыз."</string>
<string name="exit_button" msgid="5829638404777671253">"Артка"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Мүчүлүштүк"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"мүчүлүштүктөрдү аныктоо дайындарын окуу"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Унаадагы мүчүлүштүктөрдү аныктоо дайындарын окуу."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"мүчүлүштүктөрдү аныктоо дайындарын тазалоо"</string>
diff --git a/service/res/values-lo/config.xml b/service/res/values-lo/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-lo/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-lo/strings.xml b/service/res/values-lo/strings.xml
index 2052db6..2fe6c4f 100644
--- a/service/res/values-lo/strings.xml
+++ b/service/res/values-lo/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"ເພື່ອຄວາມປອດໄພຂອງທ່ານ, ກິດຈະກຳນີ້ບໍ່ມີໃຫ້ນໍາໃຊ້ໃນຂະນະທີ່ທ່ານກຳລັງຂັບລົດຢູ່. \nເພື່ອສືບຕໍ່, ກະລຸນາລໍຖ້າຈົນກວ່າວ່າທ່ານຈອດລົດ."</string>
<string name="exit_button_message" msgid="8554690915924055685">"ເພື່ອເລີ່ມຕົ້ນຄືນໃໝ່ດ້ວຍຄຸນສົມບັດແອັບທີ່ປອດໄພ, ກະລຸນາເລືອກ <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"ກັບຄືນ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ອ່ານຂໍ້ມູນການວິເຄາະ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ອ່ານຂໍ້ມູນການວິເຄາະຈາກລົດ."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ລຶບລ້າງຂໍ້ມູນການວິເຄາະ"</string>
diff --git a/service/res/values-lt/config.xml b/service/res/values-lt/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-lt/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-lt/strings.xml b/service/res/values-lt/strings.xml
index d9eca78..2342259 100644
--- a/service/res/values-lt/strings.xml
+++ b/service/res/values-lt/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Siekiant užtikrinti jūsų saugą, ši veikla nepasiekiama vairuojant.\nJei norite tęsti, palaukite, kol sustosite."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Jei norite pradėti iš naujo naudodami saugias programos funkcijas, pasirinkite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Atgal"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Der. inf."</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"nuskaityti diagnostikos duomenis"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Nuskaityti automobilio diagnostikos duomenis."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"išvalyti diagnostikos duomenis"</string>
diff --git a/service/res/values-lv/config.xml b/service/res/values-lv/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-lv/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-lv/strings.xml b/service/res/values-lv/strings.xml
index c319e52..f926f13 100644
--- a/service/res/values-lv/strings.xml
+++ b/service/res/values-lv/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Drošības apsvērumu dēļ šī darbība nav pieejama braukšanas laikā.\nTurpiniet, kad automašīna būs novietota stāvēšanai."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Lai atsāktu darbu ar drošām lietotnes funkcijām, atlasiet pogu <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Atpakaļ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"nolasīt diagnostikas datus"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Nolasīt diagnostikas datus no automašīnas."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"notīrīt diagnostikas datus"</string>
diff --git a/service/res/values-mk/config.xml b/service/res/values-mk/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-mk/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-mk/strings.xml b/service/res/values-mk/strings.xml
index c5fa0bb..b419e52 100644
--- a/service/res/values-mk/strings.xml
+++ b/service/res/values-mk/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"За ваша безбедност, оваа активност не е достапна додека возите.\nЗа да продолжите, почекајте да се паркирате."</string>
<string name="exit_button_message" msgid="8554690915924055685">"За да започнете одново со безбедносните фунции на апликацијата, изберете <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Назад"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ги чита дијагностичките податоци"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Чита дијагностички податоци од автомобилот."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"чисти дијагностички податоци"</string>
diff --git a/service/res/values-ml/config.xml b/service/res/values-ml/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ml/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ml/strings.xml b/service/res/values-ml/strings.xml
index fc9e458..6e6007f 100644
--- a/service/res/values-ml/strings.xml
+++ b/service/res/values-ml/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"നിങ്ങളുടെ സുരക്ഷയ്ക്ക്, ഡ്രൈവ് ചെയ്യുമ്പോൾ ഈ ആക്റ്റിവിറ്റി ലഭ്യമല്ല.\nതുടരാൻ, നിങ്ങൾ പാർക്ക് ചെയ്യുന്നതുവരെ കാത്തിരിക്കുക."</string>
<string name="exit_button_message" msgid="8554690915924055685">"സുരക്ഷിതമായ ആപ്പ് ഫീച്ചറുകൾ ഉപയോഗിച്ച് പുനരാരംഭിക്കാൻ, <xliff:g id="EXIT_BUTTON">%s</xliff:g> തിരഞ്ഞെടുക്കുക."</string>
<string name="exit_button" msgid="5829638404777671253">"മടങ്ങുക"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ഡീബഗ് വിവരം"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"പ്രശ്നനിർണ്ണയ ഡാറ്റ വായിക്കുക"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"കാറിൽ നിന്നുള്ള പ്രശ്നനിർണ്ണയ ഡാറ്റ വായിക്കുക."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"പ്രശ്നനിർണ്ണയ ഡാറ്റ മായ്ക്കുക"</string>
diff --git a/service/res/values-mn/config.xml b/service/res/values-mn/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-mn/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-mn/strings.xml b/service/res/values-mn/strings.xml
index 1808c32..83da614 100644
--- a/service/res/values-mn/strings.xml
+++ b/service/res/values-mn/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Таны аюулгүй байдлын үүднээс жолоодох явцад энэ үйл ажиллагааг хийх боломжгүй.\nМашинаа зогсоолд байршуулаад үргэлжлүүлнэ үү."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Аппын аюулгүй онцлогуудтайгаар дахин эхлүүлэхийн тулд <xliff:g id="EXIT_BUTTON">%s</xliff:g>-г сонгоно уу."</string>
<string name="exit_button" msgid="5829638404777671253">"Буцах"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Дебаг хийх мэдээлэл"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"оношилгооны өгөгдлийг унших"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Машины оношилгооны өгөгдлийг унших."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"оношилгооны өгөгдлийг устгах"</string>
diff --git a/service/res/values-mr/config.xml b/service/res/values-mr/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-mr/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-mr/strings.xml b/service/res/values-mr/strings.xml
index 0afb98e..efdc646 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"तुमच्या सुरक्षेसाठी, ड्रायव्हिंग करत असताना ही अॅक्टिव्हिटी उपलब्ध नाही.\nसुरू ठेवण्यासाठी, पार्क करेपर्यंत वाट पहा."</string>
<string name="exit_button_message" msgid="8554690915924055685">"सुरक्षित अॅप वैशिष्ट्यांसोबत पुन्हा सुरुवात करण्यासाठी, <xliff:g id="EXIT_BUTTON">%s</xliff:g> निवडा."</string>
<string name="exit_button" msgid="5829638404777671253">"मागे जा"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"डीबग माहिती"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"निदान डेटा वाचा"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"कारचा निदान डेटा वाचा."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"निदान डेटा साफ करा"</string>
diff --git a/service/res/values-ms/config.xml b/service/res/values-ms/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ms/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ms/strings.xml b/service/res/values-ms/strings.xml
index 23332b8..6869364 100644
--- a/service/res/values-ms/strings.xml
+++ b/service/res/values-ms/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Untuk keselamatan anda, aktiviti ini tidak tersedia semasa memandu.\nUntuk meneruskan, tunggu kereta diberhentikan."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Untuk bermula semula dengan ciri apl selamat, pilih <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Kembali"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Nyhpepijat"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"baca data diagnostik"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Baca data diagnostik daripada kereta."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"kosongkan data diagnostik"</string>
diff --git a/service/res/values-my/config.xml b/service/res/values-my/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-my/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-my/strings.xml b/service/res/values-my/strings.xml
index f62bf4e..e2e8572 100644
--- a/service/res/values-my/strings.xml
+++ b/service/res/values-my/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"သင့် လုံခြုံမှုအတွက် ဤလုပ်ဆောင်ချက်ကို ကားမောင်းနေစဉ် အသုံးမပြုနိုင်ပါ။\nဆက်လက်လုပ်ဆောင်ရန် ကားရပ်နားသည်အထိစောင့်ပါ။"</string>
<string name="exit_button_message" msgid="8554690915924055685">"စိတ်ချရသော အက်ပ်လုပ်ဆောင်ချက်များနှင့်အတူ အစမှပြန်စရန် <xliff:g id="EXIT_BUTTON">%s</xliff:g> ကို ရွေးချယ်ပါ။"</string>
<string name="exit_button" msgid="5829638404777671253">"နောက်သို့"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"တွေ့ရှိမှု"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"အမှားရှာပြင်ခြင်းဒေတာများကို ကြည့်ပါမည်"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ကားအတွင်း အမှားရှာပြင်ခြင်းဒေတာကို ကြည့်ပါမည်။"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"အမှားရှာပြင်ခြင်းဒေတာများကို ရှင်းလင်းပါမည်"</string>
diff --git a/service/res/values-nb/config.xml b/service/res/values-nb/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-nb/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-nb/strings.xml b/service/res/values-nb/strings.xml
index d273bcb..62108e6 100644
--- a/service/res/values-nb/strings.xml
+++ b/service/res/values-nb/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Av sikkerhetshensyn er denne aktiviteten utilgjengelig når du kjører.\nDu kan ikke fortsette før du stopper bilen."</string>
<string name="exit_button_message" msgid="8554690915924055685">"For å starte på nytt med sikre appfunksjoner, velg <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Tilbake"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lese diagnostikkdata"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Les diagnostikkdata fra bilen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"slette diagnostikkdata"</string>
diff --git a/service/res/values-ne/config.xml b/service/res/values-ne/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ne/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ne/strings.xml b/service/res/values-ne/strings.xml
index 5d9431c..add0fb9 100644
--- a/service/res/values-ne/strings.xml
+++ b/service/res/values-ne/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"तपाईंको सुरक्षाका लागि, तपाईंले सवारी साधन चलाइरहेका बेलामा यो क्रियाकलाप उपलब्ध हुँदैन।\nजारी राख्न, पार्क नगरुन्जेल पर्खनुहोस्।"</string>
<string name="exit_button_message" msgid="8554690915924055685">"अनुप्रयोगका सुरक्षित सुविधाहरूको प्रयोग गरी फेरि सुरु गर्न <xliff:g id="EXIT_BUTTON">%s</xliff:g> चयन गर्नुहोस्।"</string>
<string name="exit_button" msgid="5829638404777671253">"पछाडि"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"डिबगसम्बन्धी जानकारी"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"निदानसम्बन्धी डेटा पढ्ने"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"कारको निदानसम्बन्धी डेटा पढ्ने।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"निदानसम्बन्धी डेटा हटाउने"</string>
diff --git a/service/res/values-nl/config.xml b/service/res/values-nl/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-nl/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-nl/strings.xml b/service/res/values-nl/strings.xml
index 659afb0..0959bb8 100644
--- a/service/res/values-nl/strings.xml
+++ b/service/res/values-nl/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Voor jouw veiligheid is deze activiteit niet beschikbaar als je aan het rijden bent.\nJe moet parkeren om door te gaan."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Selecteer <xliff:g id="EXIT_BUTTON">%s</xliff:g> om opnieuw te beginnen met de veilige app-functies."</string>
<string name="exit_button" msgid="5829638404777671253">"Vorige"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug-info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"diagnostische gegevens lezen"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Diagnostische gegevens van auto lezen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"diagnostische gegevens wissen"</string>
diff --git a/service/res/values-or/config.xml b/service/res/values-or/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-or/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-or/strings.xml b/service/res/values-or/strings.xml
index b054470..2d90b94 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"ଆପଣଙ୍କ ସୁରକ୍ଷା ପାଇଁ, ଡ୍ରାଇଭିଂ କରିବା ସମୟରେ ଏହି ଗତିବିଧି ଉପଲବ୍ଧ ନାହିଁ।\nଜାରି ରଖିବା ପାଇଁ, ପାର୍କ କରିବା ପର୍ଯ୍ୟନ୍ତ ଅପେକ୍ଷା କରନ୍ତୁ।"</string>
<string name="exit_button_message" msgid="8554690915924055685">"ସୁରକ୍ଷିତ ଆପ୍ ବୈଶିଷ୍ଟ୍ୟଗୁଡ଼ିକୁ ନେଇ ପୁଣି ଆରମ୍ଭ କରିବା ପାଇଁ, <xliff:g id="EXIT_BUTTON">%s</xliff:g> ଚୟନ କରନ୍ତୁ।"</string>
<string name="exit_button" msgid="5829638404777671253">"ପଛକୁ ଫେରନ୍ତୁ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ଡିବଗ୍ ସୂଚନା"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ଡାଏଗ୍ନୋଷ୍ଟିକ୍ ଡାଟାକୁ ପଢ଼ିବ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"କାର୍ ମଧ୍ୟରୁ ଡାଏଗ୍ନୋଷ୍ଟିକ୍ ଡାଟାକୁ ପଢ଼ିବ।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ଡାଏଗ୍ନୋଷ୍ଟିକ୍ ଡାଟା ଖାଲି କରନ୍ତୁ"</string>
diff --git a/service/res/values-pa/config.xml b/service/res/values-pa/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-pa/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-pa/strings.xml b/service/res/values-pa/strings.xml
index 576e5b7..d3700ed 100644
--- a/service/res/values-pa/strings.xml
+++ b/service/res/values-pa/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"ਤੁਹਾਡੀ ਸੁਰੱਖਿਆ ਲਈ, ਗੱਡੀ ਚਲਾਉਣ ਵੇਲੇ ਇਹ ਸਰਗਰਮੀ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।\nਜਾਰੀ ਰੱਖਣ ਲਈ, ਗੱਡੀ ਰੋਕਣ ਤੱਕ ਉਡੀਕ ਕਰੋ।"</string>
<string name="exit_button_message" msgid="8554690915924055685">"ਸੁਰੱਖਿਅਤ ਐਪ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨਾਲ ਮੁੜ ਤੋਂ ਸ਼ੁਰੂ ਕਰਨ ਲਈ, <xliff:g id="EXIT_BUTTON">%s</xliff:g> ਚੁਣੋ।"</string>
<string name="exit_button" msgid="5829638404777671253">"ਪਿੱਛੇ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ਡੀਬੱਗ ਜਾਣਕਾਰੀ"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ਤਸ਼ਖੀਸੀ ਡਾਟੇ ਨੂੰ ਪੜ੍ਹਨਾ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ਕਾਰ ਦਾ ਤਸ਼ਖੀਸੀ ਡਾਟਾ ਪੜ੍ਹਨਾ।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ਤਸ਼ਖੀਸੀ ਡਾਟਾ ਕਲੀਅਰ ਕਰਨਾ"</string>
diff --git a/service/res/values-pl/config.xml b/service/res/values-pl/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-pl/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-pl/strings.xml b/service/res/values-pl/strings.xml
index 537d513..593181e 100644
--- a/service/res/values-pl/strings.xml
+++ b/service/res/values-pl/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Dla Twojego bezpieczeństwa ta funkcja jest wyłączona podczas jazdy.\nAby jej użyć, zaparkuj samochód."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Aby jeszcze raz przejść do funkcji bezpieczeństwa w aplikacji, wybierz <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Wstecz"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Dane debugowania"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"odczytywanie danych diagnostycznych"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Odczytywanie danych diagnostycznych samochodu."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"czyszczenie danych diagnostycznych"</string>
diff --git a/service/res/values-pt-rPT/config.xml b/service/res/values-pt-rPT/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-pt-rPT/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-pt-rPT/strings.xml b/service/res/values-pt-rPT/strings.xml
index bf327df..3ba192b 100644
--- a/service/res/values-pt-rPT/strings.xml
+++ b/service/res/values-pt-rPT/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Para sua segurança, esta atividade não está disponível enquanto estiver a conduzir.\nPode continuar após estacionar."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Para começar de novo com funcionalidades de aplicações seguras, selecione <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Anterior"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Informações de depuração"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ler os dados de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Ler os dados de diagnóstico do automóvel."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"limpar os dados de diagnóstico"</string>
diff --git a/service/res/values-pt/config.xml b/service/res/values-pt/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-pt/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-pt/strings.xml b/service/res/values-pt/strings.xml
index 5236c7b..3a002c3 100644
--- a/service/res/values-pt/strings.xml
+++ b/service/res/values-pt/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Para sua segurança, essa atividade não está disponível enquanto você dirige.\nPara continuar, aguarde até estacionar."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Para reiniciar o app com recursos de segurança, selecione <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Voltar"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Info de depuração"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ler dados de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Ler dados de diagnóstico do carro."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"limpar dados de diagnóstico"</string>
diff --git a/service/res/values-ro/config.xml b/service/res/values-ro/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ro/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ro/strings.xml b/service/res/values-ro/strings.xml
index 77d4b1e..6f48c30 100644
--- a/service/res/values-ro/strings.xml
+++ b/service/res/values-ro/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Pentru siguranța dvs., activitatea nu este disponibilă în timp ce conduceți.\nCa să continuați, așteptați să parcați."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Pentru a începe din nou cu funcțiile pentru aplicații sigure, selectați <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Înapoi"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Informații de remediere a erorilor"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"Citește datele de diagnosticare"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Citește datele de diagnosticare de la mașină."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Șterge datele de diagnosticare"</string>
diff --git a/service/res/values-ru/config.xml b/service/res/values-ru/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ru/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ru/strings.xml b/service/res/values-ru/strings.xml
index a7439e5..205d54a 100644
--- a/service/res/values-ru/strings.xml
+++ b/service/res/values-ru/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Во время вождения это действие недоступно.\nСначала вам нужно припарковаться."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Чтобы перезапустить приложение в безопасном режиме, нажмите кнопку \"<xliff:g id="EXIT_BUTTON">%s</xliff:g>\"."</string>
<string name="exit_button" msgid="5829638404777671253">"Назад"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Данные отладки"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"чтение диагностических данных"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Чтение диагностических данных автомобиля."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"удаление диагностических данных"</string>
diff --git a/service/res/values-si/config.xml b/service/res/values-si/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-si/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-si/strings.xml b/service/res/values-si/strings.xml
index 4ad1eaf..49e9ce4 100644
--- a/service/res/values-si/strings.xml
+++ b/service/res/values-si/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"ඔබේ ආරක්ෂාව සඳහා, ඔබ රිය පදවන විට මෙම ක්රියාකාරකම නොලැබේ.\nඉදිරියට යාමට, ඔබ ගාල් කරන තෙක් රැඳී සිටින්න."</string>
<string name="exit_button_message" msgid="8554690915924055685">"ආරක්ෂිත යෙදුම් විශේෂාංග සමඟ පටන් ගැනීමට, <xliff:g id="EXIT_BUTTON">%s</xliff:g> තෝරන්න."</string>
<string name="exit_button" msgid="5829638404777671253">"ආපසු"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"නිදොසීම"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"දෝෂනිර්ණ දත්ත කියවන්න"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"මෝටර් රථයෙන් දෝෂනිර්ණ දත්ත කියවන්න."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"දෝෂනිර්ණ දත්ත හිස් කරන්න"</string>
diff --git a/service/res/values-sk/config.xml b/service/res/values-sk/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-sk/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-sk/strings.xml b/service/res/values-sk/strings.xml
index 3c16be6..8e5cb3e 100644
--- a/service/res/values-sk/strings.xml
+++ b/service/res/values-sk/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Z bezpečnostných dôvodov nie je táto aktivita k dispozícii počas jazdy.\nAk chcete pokračovať, počkajte, kým budete parkovať."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Ak chcete začať odznova s bezpečnými funkciami aplikácie, vyberte tlačidlo <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Späť"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Informácie o ladení"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"čítať diagnostické údaje"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Čítanie diagnostických údajov z auta."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"vymazať diagnostické údaje"</string>
diff --git a/service/res/values-sl/config.xml b/service/res/values-sl/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-sl/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-sl/strings.xml b/service/res/values-sl/strings.xml
index f1ff307..2e00b3a 100644
--- a/service/res/values-sl/strings.xml
+++ b/service/res/values-sl/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Zaradi varnosti ta dejavnost med vožnjo ni na voljo.\nČe želite nadaljevati, počakajte, da bo vozilo parkirano."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Če želite začeti znova z varnimi funkcijami aplikacij, izberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Nazaj"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Odpr. nap."</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"branje diagnostičnih podatkov"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Branje diagnostičnih podatkov avtomobila."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"brisanje diagnostičnih podatkov"</string>
diff --git a/service/res/values-sq/config.xml b/service/res/values-sq/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-sq/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-sq/strings.xml b/service/res/values-sq/strings.xml
index 8d56e6d..f7f4684 100644
--- a/service/res/values-sq/strings.xml
+++ b/service/res/values-sq/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Për sigurinë tënde, ky aktivitet nuk ofrohet kur je duke drejtuar makinën.\nPër të vazhduar, prit deri sa të parkosh."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Për të filluar nga e para me funksionet e sigurta të aplikacionit, zgjidh <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Prapa"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Informacionet e defekteve në kod"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lexo të dhënat diagnostikuese"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lexo të dhënat diagnostikuese nga makina."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"pastro të dhënat diagnostikuese"</string>
diff --git a/service/res/values-sr/config.xml b/service/res/values-sr/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-sr/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-sr/strings.xml b/service/res/values-sr/strings.xml
index 8c58e53..0983a07 100644
--- a/service/res/values-sr/strings.xml
+++ b/service/res/values-sr/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Ова активност није доступна док возите ради ваше безбедности.\nДа бисте наставили, прво се паркирајте."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Да бисте поново почели са безбедним функцијама апликације, изаберите <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Назад"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"читање дијагностичких података"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Читање дијагностичких података из аутомобила."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"брисање дијагностичких података"</string>
diff --git a/service/res/values-sv/config.xml b/service/res/values-sv/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-sv/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-sv/strings.xml b/service/res/values-sv/strings.xml
index 32dffc1..3f0ea0c 100644
--- a/service/res/values-sv/strings.xml
+++ b/service/res/values-sv/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Av säkerhetsskäl är den här aktiviteten inte tillgänglig under körning.\nDu kan fortsätta med detta när du har parkerat."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Välj <xliff:g id="EXIT_BUTTON">%s</xliff:g> om du vill starta om appen med säkra funktioner."</string>
<string name="exit_button" msgid="5829638404777671253">"Tillbaka"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"läsa diagnostikdata"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Läsa diagnostisk data om bilen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"rensa diagnostikdata"</string>
diff --git a/service/res/values-sw/config.xml b/service/res/values-sw/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-sw/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-sw/strings.xml b/service/res/values-sw/strings.xml
index 66fa85f..0619eac 100644
--- a/service/res/values-sw/strings.xml
+++ b/service/res/values-sw/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Kwa usalama wako, shughuli haipatikani wakati unaendesha gari. \nIli uendelee, subiri hadi utakapoegesha gari."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Ili uanzishe tena ukitumia vipengele salama vya programu, chagua <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Rudi Nyuma"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"kusoma data ya uchunguzi"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Kusoma data ya uchunguzi kwenye gari."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"kufuta data ya uchunguzi wa gari"</string>
diff --git a/service/res/values-ta/config.xml b/service/res/values-ta/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ta/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ta/strings.xml b/service/res/values-ta/strings.xml
index 0fcb211..8eab4ef 100644
--- a/service/res/values-ta/strings.xml
+++ b/service/res/values-ta/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"உங்கள் பாதுகாப்பை முன்னிட்டு இந்தச் செயல்பாடு, வாகனம் ஓட்டும்போது இயங்காது.\nதொடர வாகனத்தை நிறுத்தும்வரை காத்திருக்கவும்."</string>
<string name="exit_button_message" msgid="8554690915924055685">"ஆப்ஸைப் பாதுகாப்பான அம்சங்களுடன் மீண்டும் தொடங்க <xliff:g id="EXIT_BUTTON">%s</xliff:g>ஐத் தேர்ந்தெடுக்கவும்."</string>
<string name="exit_button" msgid="5829638404777671253">"பின்செல்"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"பிழைதிருத்தத் தகவல்"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ஆய்வுத் தரவை அறிய வேண்டும்"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"கார் தொடர்பான ஆய்வுத் தரவை அறிய வேண்டும்."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ஆய்வுத் தரவை அழிக்க வேண்டும்"</string>
diff --git a/service/res/values-te/config.xml b/service/res/values-te/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-te/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-te/strings.xml b/service/res/values-te/strings.xml
index eec213e..494e476 100644
--- a/service/res/values-te/strings.xml
+++ b/service/res/values-te/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"మీ భద్రత విషయమై, ఈ కార్యాచరణ మీరు డ్రైవింగ్లో ఉన్నప్పుడు అందుబాటులో లేదు.\n కొనసాగించడానికి, మీరు పార్క్ చేయబడేవరకు వేచి ఉండండి."</string>
<string name="exit_button_message" msgid="8554690915924055685">"సురక్షిత యాప్ లక్షణాలతో ప్రారంభించడానికి, <xliff:g id="EXIT_BUTTON">%s</xliff:g>ని ఎంచుకోండి."</string>
<string name="exit_button" msgid="5829638404777671253">"వెనుకకు"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"డీబగ్ సమాచారం"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"సమస్య విశ్లేషణ డేటాను తెలుసుకోగలవు"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"కారు నుండి విశ్లేషణ డేటాను తెలుసుకోగలవు."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"సమస్య విశ్లేషణ డేటాను క్లియర్ చేయగలవు"</string>
diff --git a/service/res/values-th/config.xml b/service/res/values-th/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-th/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-th/strings.xml b/service/res/values-th/strings.xml
index e391708..197bc75 100644
--- a/service/res/values-th/strings.xml
+++ b/service/res/values-th/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"เพื่อความปลอดภัย กิจกรรมนี้จะไม่เปิดให้ใช้งานขณะขับรถ\nคุณต้องจอดรถให้เรียบร้อยก่อน จึงจะดำเนินการต่อได้"</string>
<string name="exit_button_message" msgid="8554690915924055685">"เลือก <xliff:g id="EXIT_BUTTON">%s</xliff:g> เพื่อเริ่มต้นใหม่โดยใช้ฟีเจอร์แอปที่ปลอดภัย"</string>
<string name="exit_button" msgid="5829638404777671253">"กลับ"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"อ่านข้อมูลการวินิจฉัย"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"อ่านข้อมูลการวินิจฉัยจากรถ"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ล้างข้อมูลการวินิจฉัย"</string>
diff --git a/service/res/values-tl/config.xml b/service/res/values-tl/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-tl/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-tl/strings.xml b/service/res/values-tl/strings.xml
index a453ca1..d50637f 100644
--- a/service/res/values-tl/strings.xml
+++ b/service/res/values-tl/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Para sa seguridad, hindi available ang aktibidad habang nagmamaneho.\nPara magpatuloy, maghintay hanggang sa makaparada."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Para magsimula sa mga ligtas na feature ng app, piliin ang <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Bumalik"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Impormasyon sa Pag-debug"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"basahin ang data ng mga diagnostic"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Basahin ang data ng mga diagnostic mula sa sasakyan."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"i-clear ang data ng mga diagnostic"</string>
diff --git a/service/res/values-tr/config.xml b/service/res/values-tr/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-tr/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-tr/strings.xml b/service/res/values-tr/strings.xml
index 5ad22dd..861d4cb 100644
--- a/service/res/values-tr/strings.xml
+++ b/service/res/values-tr/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Güvenliğiniz için bu etkinlik sürüş sırasında gerçekleştirilemez.\nDevam etmek için park edene dek bekleyin."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Güvenli uygulama özellikleriyle baştan başlamak için <xliff:g id="EXIT_BUTTON">%s</xliff:g> düğmesini seçin."</string>
<string name="exit_button" msgid="5829638404777671253">"Geri"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Hata Ayıklama Bilgileri"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"teşhis verilerini okuma"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Araçtan teşhis verilerini okuma."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"teşhis verilerini temizleme"</string>
diff --git a/service/res/values-uk/config.xml b/service/res/values-uk/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-uk/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-uk/strings.xml b/service/res/values-uk/strings.xml
index ca4f8b5..24fc867 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Задля вашої безпеки ці дії недоступні під час поїздки.\nЩоб продовжити, зупиніть автомобіль."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Щоб почати знову з безпечними функціями додатка, натисніть кнопку \"<xliff:g id="EXIT_BUTTON">%s</xliff:g>\"."</string>
<string name="exit_button" msgid="5829638404777671253">"Назад"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"перегляд даних діагностики"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Перегляд даних діагностики автомобіля."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"очищення даних діагностики"</string>
diff --git a/service/res/values-ur/config.xml b/service/res/values-ur/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-ur/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-ur/strings.xml b/service/res/values-ur/strings.xml
index 517ae7b..58f1aca 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"آپ کی حفاظت کے لیے یہ سرگرمی آپ کے کار چلانے کے دوران دستیاب نہیں ہے۔\n جاری رکھنے کے لیے کار کے پارک ہونے تک انتظار کریں۔"</string>
<string name="exit_button_message" msgid="8554690915924055685">"محفوظ اپپ کی خصوصیات کے ساتھ شروع کرنے کے لیے <xliff:g id="EXIT_BUTTON">%s</xliff:g> پر کلک کریں۔"</string>
<string name="exit_button" msgid="5829638404777671253">"پیچھے"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ڈیبگ کی معلومات"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"تشخیصی ڈیٹا پڑھیں"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"کار کے تشخیصی ڈیٹا کے بارے میں پڑھیں۔"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"تشخیصی ڈیٹا صاف کریں"</string>
diff --git a/service/res/values-uz/config.xml b/service/res/values-uz/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-uz/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-uz/strings.xml b/service/res/values-uz/strings.xml
index 893ba9d..f6bfb87 100644
--- a/service/res/values-uz/strings.xml
+++ b/service/res/values-uz/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Avtomobil haydayotganingizda bu harakatni amalga oshira olmaysiz.\nUni bajarish uchun avtomobilni toʻxtating."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Ilovani xavfsiz rejimda ishga tushirish uchun <xliff:g id="EXIT_BUTTON">%s</xliff:g> tugmasini bosing."</string>
<string name="exit_button" msgid="5829638404777671253">"Orqaga"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"diagnostika axborotini ochish"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Avtomobildan diagnostika axborotini olish."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"diagnostika axborotini tozalash"</string>
diff --git a/service/res/values-vi/config.xml b/service/res/values-vi/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-vi/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-vi/strings.xml b/service/res/values-vi/strings.xml
index 265173b..57be52a 100644
--- a/service/res/values-vi/strings.xml
+++ b/service/res/values-vi/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Vì lý do an toàn, bạn không sử dụng được hoạt động này trong khi lái xe.\nHãy đợi cho tới khi bạn đỗ xe để tiếp tục."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Để bắt đầu lại với các tính năng an toàn của ứng dụng, hãy chọn <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Quay lại"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Thông tin gỡ lỗi"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"đọc dữ liệu chẩn đoán"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Đọc dữ liệu chẩn đoán từ ô tô."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"xóa dữ liệu chẩn đoán"</string>
diff --git a/service/res/values-zh-rCN/config.xml b/service/res/values-zh-rCN/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-zh-rCN/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-zh-rCN/strings.xml b/service/res/values-zh-rCN/strings.xml
index ad55cda..b30acc4 100644
--- a/service/res/values-zh-rCN/strings.xml
+++ b/service/res/values-zh-rCN/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"为了确保您的安全,您无法在开车时执行这项活动。\n要继续,请先停车。"</string>
<string name="exit_button_message" msgid="8554690915924055685">"要重新开始使用安全的应用功能,请选择<xliff:g id="EXIT_BUTTON">%s</xliff:g>。"</string>
<string name="exit_button" msgid="5829638404777671253">"返回"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"调试信息"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"读取诊断数据"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"读取汽车的诊断数据。"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"清除诊断数据"</string>
diff --git a/service/res/values-zh-rHK/config.xml b/service/res/values-zh-rHK/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-zh-rHK/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-zh-rHK/strings.xml b/service/res/values-zh-rHK/strings.xml
index 0dca2f2..e344bfb 100644
--- a/service/res/values-zh-rHK/strings.xml
+++ b/service/res/values-zh-rHK/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"基於安全理由,駕駛時無法執行此操作。\n如要繼續,請留待泊車後操作。"</string>
<string name="exit_button_message" msgid="8554690915924055685">"如要以安全應用程式功能重新啟動,請選擇 <xliff:g id="EXIT_BUTTON">%s</xliff:g>。"</string>
<string name="exit_button" msgid="5829638404777671253">"返回"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"讀取診斷資料"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"讀取來自汽車的診斷資料。"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"清除診斷資料"</string>
diff --git a/service/res/values-zh-rTW/config.xml b/service/res/values-zh-rTW/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-zh-rTW/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-zh-rTW/strings.xml b/service/res/values-zh-rTW/strings.xml
index ffb8cc4..1848811 100644
--- a/service/res/values-zh-rTW/strings.xml
+++ b/service/res/values-zh-rTW/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"為了你的安全,開車期間不得進行這個活動。\n如要繼續,請先停車。"</string>
<string name="exit_button_message" msgid="8554690915924055685">"如要使用安全應用程式功能重新啟動,請選取「離開」按鈕 <xliff:g id="EXIT_BUTTON">%s</xliff:g>。"</string>
<string name="exit_button" msgid="5829638404777671253">"返回"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"偵錯資訊"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"讀取診斷資料"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"讀取車輛的診斷資料。"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"清除診斷資料"</string>
diff --git a/service/res/values-zu/config.xml b/service/res/values-zu/config.xml
deleted file mode 100644
index f2b960f..0000000
--- a/service/res/values-zu/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="2416852774232083347">"android.car.cluster.sample/.ClusterRenderingServiceImpl"</string>
- <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
- <string name="activityWhitelist" msgid="1814434236909655273"></string>
- <!-- no translation found for systemActivityWhitelist (1256445723884668706) -->
- <skip />
- <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-zu/strings.xml b/service/res/values-zu/strings.xml
index 9966b54..7225857 100644
--- a/service/res/values-zu/strings.xml
+++ b/service/res/values-zu/strings.xml
@@ -69,7 +69,6 @@
<string name="activity_blocked_text" msgid="5342114426610711378">"Ngokuphepha kwakho, lo msebenzi awutholakali uma ushayela.\nUkuze uqhubeke, linda uze umiswe."</string>
<string name="exit_button_message" msgid="8554690915924055685">"Ukuze uqalise futhi ngezici zohlelo lokusebenza, khetha <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="5829638404777671253">"Emuva"</string>
- <string name="debug_button_text" msgid="6395881820644544676">"ulwazi Lokususa iphutha"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"funda idatha yokuxilonga"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Ukufunda idatha yokuxilonga kusuka emotweni."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"sula idatha yokuxilonga"</string>
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 886e3ba..4aef4a5 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -38,23 +38,24 @@
connection process. Disable this default to implement your own policy. -->
<bool name="useDefaultBluetoothConnectionPolicy">true</bool>
- <string name="inputService">android.car.input.service/.DefaultInputService</string>
+ <string name="inputService" translatable="false">android.car.input.service/.DefaultInputService</string>
- <string name="instrumentClusterRendererService">android.car.cluster.sample/.ClusterRenderingServiceImpl</string>
+ <!-- Service responsible for displaying information on the car instrument cluster. -->
+ <string name="instrumentClusterRendererService" translatable="false">android.car.cluster/.ClusterRenderingService</string>
<!-- Whether to enable Activity blocking for safety. When Activity blocking is enabled,
only whitelisted safe Activities will be allowed while car is not parked. -->
<bool name="enableActivityBlockingForSafety">true</bool>
<!-- Activity to be presented when un-safe activity is launched. Take a look at the javadoc of the
default implementation. -->
- <string name="activityBlockingActivity">com.android.car/com.android.car.pm.ActivityBlockingActivity</string>
+ <string name="activityBlockingActivity" translatable="false">com.android.car/com.android.car.pm.ActivityBlockingActivity</string>
<!-- Comma separated list of activities that need to be exempted from getting
blocked in a UX restricted state.
Format of each entry is either to specify package name to whitelist the whole package or
use format of "packagename/activity_classname" for tagging each activities.
For general guidelines to design distraction optimized apps, please refer
to Android Auto Driver Distraction Guidelines. -->
- <string name="activityWhitelist"></string>
+ <string name="activityWhitelist" translatable="false"></string>
<!-- Comma separated list of activities that need to be exempted from getting
blocked in a UX restricted state.
Format of each entry is either to specify package name to whitelist the whole package or
@@ -62,16 +63,16 @@
The current implementations expects the following system packages/activities to be
whitelisted. For general guidelines to design distraction optimized apps, please refer
to Android Auto Driver Distraction Guidelines. -->
- <string name="systemActivityWhitelist">com.android.systemui,com.google.android.permissioncontroller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,android/com.android.internal.app.ResolverActivity</string>
+ <string name="systemActivityWhitelist" translatable="false">com.android.systemui,com.google.android.permissioncontroller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,android/com.android.internal.app.ResolverActivity</string>
<!-- Comma separated list of activities that will be blocked during restricted state.
Format of each entry is either to specify package name to whitelist the whole package
or use format of "packagename/activity_classname" for tagging each activities.-->
- <string name="activityBlacklist"></string>
+ <string name="activityBlacklist" translatable="false"></string>
<!-- List of play store package names that are allowed sources of app installation-->
- <string-array translateble="false" name="allowedAppInstallSources">
+ <string-array translatable="false" name="allowedAppInstallSources">
</string-array>
<!-- Default home activity -->
- <string name="defaultHomeActivity"><!--com.your.package/com.your.package.Activity--></string>
+ <string name="defaultHomeActivity" translatable="false"><!--com.your.package/com.your.package.Activity--></string>
<!-- The com.android.car.vms.VmsClientManager will bind to this list of clients running as system user -->
<string-array translatable="false" name="vmsPublisherSystemClients">
</string-array>
@@ -95,7 +96,7 @@
no activity shall be launched, or must be in the format of a flattened ComponentName and
reference a valid activity. It is strongly recommended that the chosen activity be
protected with the android.car.permission.STORAGE_MONITORING permission. -->
- <string name="activityHandlerForFlashWearChanges">com.google.android.car.defaultstoragemonitoringcompanionapp/.MainActivity</string>
+ <string name="activityHandlerForFlashWearChanges" translatable="false">com.google.android.car.defaultstoragemonitoringcompanionapp/.MainActivity</string>
<!-- How often (in seconds) CarService will update I/O metrics from the kernel. -->
<integer name="ioStatsRefreshRateSeconds">60</integer>
@@ -128,7 +129,7 @@
must be registered in its containing app's AndroidManifest.xml and it is
strongly recommended that it be protected with the
android.car.permission.STORAGE_MONITORING permission. -->
- <string name="intentReceiverForUnacceptableIoMetrics">com.google.android.car.defaultstoragemonitoringcompanionapp/.ExcessiveIoIntentReceiver</string>
+ <string name="intentReceiverForUnacceptableIoMetrics" translatable="false">com.google.android.car.defaultstoragemonitoringcompanionapp/.ExcessiveIoIntentReceiver</string>
<!-- The Model ID to advertise Bluetooth Fast Pair connections with. Must be overlayed with
device specific model id. -->
@@ -201,8 +202,8 @@
<!-- service/characteristics uuid for unlocking a device -->
<string name="unlock_service_uuid" translatable="false">00003ac5-0000-1000-8000-00805f9b34fb</string>
- <string name="unlock_escrow_token_uuid" translatable="false">5e2a68a2-27be-43f9-8d1e-4546976fabd7</string>
- <string name="unlock_handle_uuid" translatable="false">5e2a68a3-27be-43f9-8d1e-4546976fabd7</string>
+ <string name="unlock_client_write_uuid" translatable="false">5e2a68a2-27be-43f9-8d1e-4546976fabd7</string>
+ <string name="unlock_server_write_uuid" translatable="false">5e2a68a3-27be-43f9-8d1e-4546976fabd7</string>
<string name="token_handle_shared_preferences" translatable="false">com.android.car.trust.TOKEN_HANDLE</string>
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index acc7a58..3d8a402 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -120,8 +120,8 @@
<string name="exit_button_message">To start over with safe app features, select <xliff:g id="exit_button" example="Back">%s</xliff:g>.</string>
<!-- Blocking activity: Text for button that restarts the current blocked application. [CHAR LIMIT=15] -->
<string name="exit_button">Back</string>
- <!-- Blocking activity: Text for button that shows debug info for non-user build. [CHAR LIMIT=10] -->
- <string name="debug_button_text">Debug Info</string>
+ <!-- Blocking activity: Text for button that shows debug info in non-user build. -->
+ <string name="debug_button_text" translatable="false">Debug Info</string>
<!-- Permission text: apps can control diagnostic data [CHAR LIMIT=NONE] -->
<string name="car_permission_label_diag_read">read diagnostic data</string>
@@ -261,4 +261,8 @@
<!-- The package name of the media application that will be selected as the default [CHAR LIMIT=NONE] -->
<string name="default_media_application" translatable="false">com.android.bluetooth</string>
+ <!-- The package name of the default bugreport application that can use CarBugreportServiceManager.
+ There is no default bugreporting app.-->
+ <string name="default_car_bugreport_application" translatable="false"></string>
+
</resources>
diff --git a/service/res/xml/car_ux_restrictions_map.xml b/service/res/xml/car_ux_restrictions_map.xml
index 385869a..813796b 100644
--- a/service/res/xml/car_ux_restrictions_map.xml
+++ b/service/res/xml/car_ux_restrictions_map.xml
@@ -55,7 +55,6 @@
<DrivingState car:state="moving" car:minSpeed="5.0">
<Restrictions car:requiresDistractionOptimization="true" car:uxr="fully_restricted"/>
</DrivingState>
-
</RestrictionMapping>
<!-- Configure restriction parameters here-->
@@ -66,4 +65,4 @@
<ContentRestrictions car:maxCumulativeItems="21" car:maxDepth="3"/>
</RestrictionParameters>
-</UxRestrictions>
\ No newline at end of file
+</UxRestrictions>
diff --git a/service/src/com/android/car/CarBugreportManagerService.java b/service/src/com/android/car/CarBugreportManagerService.java
index 25592e8..338ca43 100644
--- a/service/src/com/android/car/CarBugreportManagerService.java
+++ b/service/src/com/android/car/CarBugreportManagerService.java
@@ -21,12 +21,14 @@
import android.car.ICarBugreportCallback;
import android.car.ICarBugreportService;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
-import android.os.Build;
+import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -35,8 +37,6 @@
import com.android.internal.annotations.GuardedBy;
-import libcore.io.IoUtils;
-
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -63,6 +63,11 @@
// The socket at /dev/socket/dumpstate to communicate with dumpstate.
private static final String DUMPSTATE_SOCKET = "dumpstate";
+ // The socket definitions must match the actual socket names defined in car_bugreportd service
+ // definition.
+ private static final String BUGREPORT_PROGRESS_SOCKET = "car_br_progress_socket";
+ private static final String BUGREPORT_OUTPUT_SOCKET = "car_br_output_socket";
+
private static final int SOCKET_CONNECTION_MAX_RETRY = 10;
/**
@@ -76,47 +81,130 @@
@Override
public void init() {
- // Initialize handler only if build is debuggable.
- if (Build.IS_DEBUGGABLE) {
- mHandlerThread = new HandlerThread(TAG);
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
- }
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
}
@Override
public void release() {
- if (mHandlerThread != null) {
- mHandlerThread.quitSafely();
- }
+ mHandlerThread.quitSafely();
}
@Override
@RequiresPermission(android.Manifest.permission.DUMP)
- public void requestBugreport(ParcelFileDescriptor pfd, ICarBugreportCallback callback) {
- if (mHandler == null) {
- // bugreport manager service is only available if the build is not a user build.
- reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_SERVICE_NOT_AVAILABLE);
- return;
+ public void requestZippedBugreport(ParcelFileDescriptor data, ParcelFileDescriptor progress,
+ ICarBugreportCallback callback) {
+
+ // Check the caller has proper permission
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
+ "requestZippedBugreport");
+ // Check the caller is signed with platform keys
+ PackageManager pm = mContext.getPackageManager();
+ int callingUid = Binder.getCallingUid();
+ if (pm.checkSignatures(Process.myUid(), callingUid) != PackageManager.SIGNATURE_MATCH) {
+ throw new SecurityException("Caller " + pm.getNameForUid(callingUid)
+ + " does not have the right signature");
+ }
+ // Check the caller is the default designated bugreport app
+ String defaultAppPkgName = mContext.getString(R.string.default_car_bugreport_application);
+ String[] packageNamesForCallerUid = pm.getPackagesForUid(callingUid);
+ boolean found = false;
+ if (packageNamesForCallerUid != null) {
+ for (String packageName : packageNamesForCallerUid) {
+ if (defaultAppPkgName.equals(packageName)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ throw new SecurityException("Caller " + pm.getNameForUid(callingUid)
+ + " is not a designated bugreport app");
}
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
- "requestBugreport");
-
synchronized (mLock) {
- requestBugReportLocked(pfd, callback);
+ requestZippedBugReportLocked(data, progress, callback);
}
}
@GuardedBy("mLock")
- private void requestBugReportLocked(ParcelFileDescriptor pfd, ICarBugreportCallback callback) {
+ private void requestZippedBugReportLocked(ParcelFileDescriptor data,
+ ParcelFileDescriptor progress, ICarBugreportCallback callback) {
if (mIsServiceRunning) {
Slog.w(TAG, "Bugreport Service already running");
reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_IN_PROGRESS);
return;
}
mIsServiceRunning = true;
- mHandler.post(() -> dumpStateToFileWrapper(pfd, callback));
+ mHandler.post(() -> startBugreportd(data, progress, callback));
+ }
+
+ private void startBugreportd(ParcelFileDescriptor data, ParcelFileDescriptor progress,
+ ICarBugreportCallback callback) {
+ readBugreport(data, progress, callback);
+ synchronized (mLock) {
+ mIsServiceRunning = false;
+ }
+ }
+
+ private void readBugreport(ParcelFileDescriptor output, ParcelFileDescriptor progress,
+ ICarBugreportCallback callback) {
+ Slog.i(TAG, "Starting car-bugreportd");
+ try {
+ SystemProperties.set("ctl.start", "car-bugreportd");
+ } catch (RuntimeException e) {
+ Slog.e(TAG, "Failed to start car-bugreportd", e);
+ reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_FAILED);
+ return;
+ }
+ // The native service first generates the progress data. Once it writes the progress
+ // data fully, it closes the socket and writes the zip file. So we read both files
+ // sequentially here.
+ if (!readSocket(BUGREPORT_PROGRESS_SOCKET, progress, callback)) {
+ Slog.e(TAG, "failed reading bugreport progress socket");
+ reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_FAILED);
+ return;
+ }
+ if (!readSocket(BUGREPORT_OUTPUT_SOCKET, output, callback)) {
+ Slog.i(TAG, "failed reading bugreport output socket");
+ reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_FAILED);
+ return;
+ }
+ Slog.i(TAG, "finished reading bugreport");
+ try {
+ callback.onFinished();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "onFinished() failed: " + e.getMessage());
+ }
+ }
+
+ private boolean readSocket(String name, ParcelFileDescriptor pfd,
+ ICarBugreportCallback callback) {
+ LocalSocket localSocket;
+
+ try {
+ localSocket = connectSocket(name);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed connecting to socket " + name, e);
+ reportError(callback,
+ CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED);
+ // Early out if connection to socket fails.
+ return false;
+ }
+
+ try (
+ DataInputStream in = new DataInputStream(localSocket.getInputStream());
+ DataOutputStream out =
+ new DataOutputStream(new ParcelFileDescriptor.AutoCloseOutputStream(pfd));
+ ) {
+ rawCopyStream(out, in);
+ } catch (IOException | RuntimeException e) {
+ Slog.e(TAG, "Failed to grab dump state " + name, e);
+ reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_FAILED);
+ return false;
+ }
+ return true;
}
private void reportError(ICarBugreportCallback callback, int errorCode) {
@@ -129,62 +217,10 @@
@Override
public void dump(PrintWriter writer) {
+ // TODO(sgurun) implement
}
- private void dumpStateToFileWrapper(ParcelFileDescriptor pfd, ICarBugreportCallback callback) {
- dumpStateToFile(pfd, callback);
- synchronized (mLock) {
- mIsServiceRunning = false;
- }
- }
-
- private void dumpStateToFile(ParcelFileDescriptor pfd, ICarBugreportCallback callback) {
- if (DEBUG) {
- Slog.d(TAG, "Dumpstate to file");
- }
- OutputStream out = null;
- InputStream in = null;
- LocalSocket localSocket;
-
- try {
- SystemProperties.set("ctl.start", "dumpstate");
- } catch (RuntimeException e) {
- Slog.e(TAG, "Failed to start dumpstate", e);
- reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_FAILED);
- return;
- }
-
- try {
- localSocket = connectToDumpstateService();
- } catch (IOException e) {
- Slog.e(TAG, "Timed out connecting to dumpstate socket", e);
- reportError(callback,
- CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED);
- // Early out if connection to socket fails.
- return;
- }
-
- try {
- in = new DataInputStream(localSocket.getInputStream());
- out = new DataOutputStream(new ParcelFileDescriptor.AutoCloseOutputStream(pfd));
- rawCopyStream(out, in);
- } catch (IOException | RuntimeException e) {
- Slog.e(TAG, "Failed to grab dump state", e);
- reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_FAILED);
- return;
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- }
-
- try {
- callback.onFinished();
- } catch (RemoteException e) {
- Slog.e(TAG, "onFinished() failed: " + e.getMessage());
- }
- }
-
- private LocalSocket connectToDumpstateService() throws IOException {
+ private LocalSocket connectSocket(String socketName) throws IOException {
LocalSocket socket = new LocalSocket();
// The dumpstate socket will be created by init upon receiving the
// service request. It may not be ready by this point. So we will
@@ -195,14 +231,15 @@
// first time too.
SystemClock.sleep(/* ms= */ 1000);
try {
- socket.connect(new LocalSocketAddress(DUMPSTATE_SOCKET,
+ socket.connect(new LocalSocketAddress(socketName,
LocalSocketAddress.Namespace.RESERVED));
return socket;
} catch (IOException e) {
if (++retryCount >= SOCKET_CONNECTION_MAX_RETRY) {
throw e;
}
- Log.i(TAG, "Failed to connect to dumpstate, will try again: " + e.getMessage());
+ Log.i(TAG, "Failed to connect to" + socketName + ". will try again"
+ + e.getMessage());
}
}
}
diff --git a/service/src/com/android/car/CarDrivingStateService.java b/service/src/com/android/car/CarDrivingStateService.java
index bc0fbc1..48840b7 100644
--- a/service/src/com/android/car/CarDrivingStateService.java
+++ b/service/src/com/android/car/CarDrivingStateService.java
@@ -17,6 +17,7 @@
package com.android.car;
import android.annotation.Nullable;
+import android.car.Car;
import android.car.VehicleAreaType;
import android.car.drivingstate.CarDrivingStateEvent;
import android.car.drivingstate.CarDrivingStateEvent.CarDrivingState;
@@ -220,6 +221,15 @@
return mCurrentDrivingState;
}
+ @Override
+ public synchronized void injectDrivingState(CarDrivingStateEvent event) {
+ ICarImpl.assertPermission(mContext, Car.PERMISSION_CONTROL_APP_BLOCKING);
+
+ for (DrivingStateClient client : mDrivingStateClients) {
+ client.dispatchEventToClients(event);
+ }
+ }
+
/**
* Class that holds onto client related information - listener interface, process that hosts the
* binder object etc.
diff --git a/service/src/com/android/car/CarLocationService.java b/service/src/com/android/car/CarLocationService.java
index ad86741..cc57856 100644
--- a/service/src/com/android/car/CarLocationService.java
+++ b/service/src/com/android/car/CarLocationService.java
@@ -16,6 +16,8 @@
package com.android.car;
+import android.car.drivingstate.CarDrivingStateEvent;
+import android.car.drivingstate.ICarDrivingStateChangeListener;
import android.car.hardware.power.CarPowerManager;
import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
import android.car.hardware.power.CarPowerManager.CarPowerStateListenerWithCompletion;
@@ -52,8 +54,8 @@
* This service stores the last known location from {@link LocationManager} when a car is parked
* and restores the location when the car is powered on.
*/
-public class CarLocationService extends BroadcastReceiver implements
- CarServiceBase, CarPowerStateListenerWithCompletion {
+public class CarLocationService extends BroadcastReceiver implements CarServiceBase,
+ CarPowerStateListenerWithCompletion {
private static final String TAG = "CarLocationService";
private static final String FILENAME = "location_cache.json";
private static final boolean DBG = true;
@@ -73,10 +75,9 @@
private HandlerThread mHandlerThread;
private Handler mHandler;
private CarPowerManager mCarPowerManager;
+ private CarDrivingStateService mCarDrivingStateService;
- public CarLocationService(
- Context context,
- CarUserManagerHelper carUserManagerHelper) {
+ public CarLocationService(Context context, CarUserManagerHelper carUserManagerHelper) {
logd("constructed");
mContext = context;
mCarUserManagerHelper = carUserManagerHelper;
@@ -90,6 +91,16 @@
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
filter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION);
mContext.registerReceiver(this, filter);
+ mCarDrivingStateService = CarLocalServices.getService(CarDrivingStateService.class);
+ if (mCarDrivingStateService != null) {
+ CarDrivingStateEvent event = mCarDrivingStateService.getCurrentDrivingState();
+ if (event != null && event.eventValue == CarDrivingStateEvent.DRIVING_STATE_MOVING) {
+ deleteCacheFile();
+ } else {
+ mCarDrivingStateService.registerDrivingStateChangeListener(
+ mICarDrivingStateChangeEventListener);
+ }
+ }
mCarPowerManager = CarLocalServices.createCarPowerManager(mContext);
if (mCarPowerManager != null) { // null case happens for testing.
mCarPowerManager.setListenerWithCompletion(CarLocationService.this);
@@ -102,6 +113,10 @@
if (mCarPowerManager != null) {
mCarPowerManager.clearListener();
}
+ if (mCarDrivingStateService != null) {
+ mCarDrivingStateService.unregisterDrivingStateChangeListener(
+ mICarDrivingStateChangeEventListener);
+ }
mContext.unregisterReceiver(this);
}
@@ -125,6 +140,11 @@
}
});
break;
+ case CarPowerStateListener.SUSPEND_EXIT:
+ deleteCacheFile();
+ if (future != null) {
+ future.complete(null);
+ }
default:
// This service does not need to do any work for these events but should still
// notify the CarPowerManager that it may proceed.
@@ -153,7 +173,7 @@
boolean locationEnabled = locationManager.isLocationEnabled();
logd("isLocationEnabled(): " + locationEnabled);
if (!locationEnabled) {
- asyncOperation(() -> deleteCacheFile());
+ deleteCacheFile();
}
} else if (action == LocationManager.PROVIDERS_CHANGED_ACTION
&& shouldCheckLocationPermissions()) {
@@ -163,11 +183,27 @@
locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
logd("isProviderEnabled('gps'): " + gpsEnabled);
if (!gpsEnabled) {
- asyncOperation(() -> deleteCacheFile());
+ deleteCacheFile();
}
}
}
+ private final ICarDrivingStateChangeListener mICarDrivingStateChangeEventListener =
+ new ICarDrivingStateChangeListener.Stub() {
+ @Override
+ public void onDrivingStateChanged(CarDrivingStateEvent event) {
+ logd("onDrivingStateChanged " + event);
+ if (event != null
+ && event.eventValue == CarDrivingStateEvent.DRIVING_STATE_MOVING) {
+ deleteCacheFile();
+ if (mCarDrivingStateService != null) {
+ mCarDrivingStateService.unregisterDrivingStateChangeListener(
+ mICarDrivingStateChangeEventListener);
+ }
+ }
+ }
+ };
+
/**
* Tells whether or not we should check location permissions for the sake of deleting the
* location cache file when permissions are lacking. If the system user is headless but the
@@ -188,7 +224,6 @@
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location == null) {
logd("Not storing null location");
- deleteCacheFile();
} else {
logd("Storing location: " + location);
AtomicFile atomicFile = new AtomicFile(getLocationCacheFile());
@@ -250,6 +285,7 @@
long currentTime = System.currentTimeMillis();
if (location.getTime() + TTL_THIRTY_DAYS_MS < currentTime) {
logd("Location expired.");
+ deleteCacheFile();
} else {
location.setTime(currentTime);
long elapsedTime = SystemClock.elapsedRealtimeNanos();
@@ -297,7 +333,6 @@
}
}
reader.endObject();
- deleteCacheFile();
} catch (FileNotFoundException e) {
Log.d(TAG, "Location cache file not found.");
} catch (IOException e) {
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index a4e0d6e..5728bf2 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -34,6 +34,8 @@
import android.media.session.MediaSessionManager;
import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
import android.media.session.PlaybackState;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.service.media.MediaBrowserService;
@@ -81,10 +83,15 @@
// null if playback has not been started yet.
private MediaController mActiveUserMediaController;
private SessionChangedListener mSessionsListener;
+ private boolean mStartPlayback;
private RemoteCallbackList<ICarMediaSourceListener> mMediaSourceListeners =
new RemoteCallbackList();
+ // Handler to receive PlaybackState callbacks from the active media controller.
+ private Handler mHandler;
+ private HandlerThread mHandlerThread;
+
/** The package name of the last media source that was removed while being primary. */
private String mRemovedMediaSourcePackage;
@@ -128,6 +135,10 @@
mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
mMediaSessionUpdater = new MediaSessionUpdater();
+ mHandlerThread = new HandlerThread(CarLog.TAG_MEDIA);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
@@ -147,6 +158,8 @@
CarLocalServices.getService(CarUserService.class).runOnUser0Unlock(() -> {
mSharedPrefs = mContext.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
mPrimaryMediaPackage = getLastMediaPackage();
+ mStartPlayback = mSharedPrefs.getInt(PLAYBACK_STATE_KEY, PlaybackState.STATE_NONE)
+ == PlaybackState.STATE_PLAYING;
notifyListeners();
});
}
@@ -217,6 +230,18 @@
}
/**
+ * Attempts to play the current source using MediaController.TransportControls.play()
+ */
+ private void play() {
+ if (mActiveUserMediaController != null) {
+ TransportControls controls = mActiveUserMediaController.getTransportControls();
+ if (controls != null) {
+ controls.play();
+ }
+ }
+ }
+
+ /**
* Attempts to stop the current source using MediaController.TransportControls.stop()
*/
private void stop() {
@@ -331,6 +356,7 @@
stop();
+ mStartPlayback = false;
mPrimaryMediaPackage = packageName;
updateActiveMediaController(mMediaSessionManager
.getActiveSessionsForUser(null, ActivityManager.getCurrentUser()));
@@ -364,6 +390,8 @@
@Override
public void onPlaybackStateChanged(PlaybackState state) {
savePlaybackState(state);
+ // Try to start playback if the new state allows the play action
+ maybeRestartPlayback(state);
}
};
@@ -442,9 +470,24 @@
return new ArrayDeque(Arrays.asList(packageNames));
}
- private void savePlaybackState(PlaybackState state) {
- mSharedPrefs.edit().putInt(PLAYBACK_STATE_KEY, state != null ? state.getState()
- : PlaybackState.STATE_NONE).apply();
+ private void savePlaybackState(PlaybackState playbackState) {
+ int state = playbackState != null ? playbackState.getState() : PlaybackState.STATE_NONE;
+ if (state == PlaybackState.STATE_PLAYING) {
+ // No longer need to request play if audio was resumed already via some other means,
+ // e.g. Assistant starts playback, user uses hardware button, etc.
+ mStartPlayback = false;
+ }
+ if (mSharedPrefs != null) {
+ mSharedPrefs.edit().putInt(PLAYBACK_STATE_KEY, state).apply();
+ }
+ }
+
+ private void maybeRestartPlayback(PlaybackState state) {
+ if (mStartPlayback && state != null
+ && (state.getActions() & PlaybackState.ACTION_PLAY) != 0) {
+ play();
+ mStartPlayback = false;
+ }
}
/**
@@ -462,8 +505,14 @@
for (MediaController controller : mediaControllers) {
if (mPrimaryMediaPackage.equals(controller.getPackageName())) {
mActiveUserMediaController = controller;
- savePlaybackState(mActiveUserMediaController.getPlaybackState());
- mActiveUserMediaController.registerCallback(mMediaControllerCallback);
+ // Specify Handler to receive callbacks on, to avoid defaulting to the calling
+ // thread; this method can be called from the MediaSessionManager callback.
+ // Using the version of this method without passing a handler causes a
+ // RuntimeException for failing to create a Handler.
+ PlaybackState state = mActiveUserMediaController.getPlaybackState();
+ savePlaybackState(state);
+ mActiveUserMediaController.registerCallback(mMediaControllerCallback, mHandler);
+ maybeRestartPlayback(state);
return;
}
}
diff --git a/service/src/com/android/car/CarProjectionService.java b/service/src/com/android/car/CarProjectionService.java
index 33ed8f6..144804e 100644
--- a/service/src/com/android/car/CarProjectionService.java
+++ b/service/src/com/android/car/CarProjectionService.java
@@ -17,6 +17,7 @@
import static android.car.CarProjectionManager.ProjectionAccessPointCallback.ERROR_GENERIC;
import static android.car.projection.ProjectionStatus.PROJECTION_STATE_INACTIVE;
+import static android.car.projection.ProjectionStatus.PROJECTION_STATE_READY_TO_PROJECT;
import static android.net.wifi.WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_FAILURE_REASON;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
@@ -410,7 +411,15 @@
ProjectionReceiverClient client = getOrCreateProjectionReceiverClientLocked(token);
client.mProjectionStatus = status;
- if (status.isActive() || TextUtils.equals(packageName, mCurrentProjectionPackage)) {
+ // If the projection package that's reporting its projection state is the currently
+ // active projection package, update the state. If it is a different package, update the
+ // current projection state if the new package is reporting that it is projecting or if
+ // it is reporting that it's ready to project, and the current package has an inactive
+ // projection state.
+ if (status.isActive()
+ || (status.getState() == PROJECTION_STATE_READY_TO_PROJECT
+ && mCurrentProjectionState == PROJECTION_STATE_INACTIVE)
+ || TextUtils.equals(packageName, mCurrentProjectionPackage)) {
mCurrentProjectionState = status.getState();
mCurrentProjectionPackage = packageName;
}
diff --git a/service/src/com/android/car/CarUxRestrictionsManagerService.java b/service/src/com/android/car/CarUxRestrictionsManagerService.java
index a9c4fbf..0c87ac4 100644
--- a/service/src/com/android/car/CarUxRestrictionsManagerService.java
+++ b/service/src/com/android/car/CarUxRestrictionsManagerService.java
@@ -304,7 +304,7 @@
* Registers a {@link ICarUxRestrictionsChangeListener} to be notified for changes to the UX
* restrictions.
*
- * @param listener Listener to register
+ * @param listener Listener to register
* @param displayId UX restrictions on this display will be notified.
*/
@Override
@@ -377,9 +377,15 @@
* @param displayId UX restrictions on this display will be returned.
*/
@Override
- @Nullable
public synchronized CarUxRestrictions getCurrentUxRestrictions(int displayId) {
- return mCurrentUxRestrictions.get(getPhysicalPort(displayId));
+ CarUxRestrictions restrictions = mCurrentUxRestrictions.get(getPhysicalPort(displayId));
+ if (restrictions == null) {
+ Log.e(TAG, String.format(
+ "Restrictions are null for displayId:%d. Returning full restrictions.",
+ displayId));
+ restrictions = createFullyRestrictedRestrictions();
+ }
+ return restrictions;
}
/**
@@ -421,7 +427,6 @@
*
* @param mode See values in {@link CarUxRestrictionsManager.UxRestrictionMode}.
* @return {@code true} if mode was successfully changed; {@code false} otherwise.
- *
* @see CarUxRestrictionsConfiguration.DrivingStateRestrictions
* @see CarUxRestrictionsConfiguration.Builder
*/
@@ -742,7 +747,10 @@
logd("dispatching to clients");
for (UxRestrictionsClient client : mUxRClients) {
- byte clientDisplayPort = getPhysicalPort(client.mDisplayId);
+ Byte clientDisplayPort = getPhysicalPort(client.mDisplayId);
+ if (clientDisplayPort == null) {
+ clientDisplayPort = mDefaultDisplayPhysicalPort;
+ }
if (displayToDispatch.contains(clientDisplayPort)) {
client.dispatchEventToClients(newUxRestrictions.get(clientDisplayPort));
}
@@ -849,12 +857,17 @@
}
}
- private byte getPhysicalPort(int displayId) {
+ /**
+ * Returns the physical port byte id for the display or {@code null} if {@link
+ * DisplayManager#getDisplay(int)} is not aware of the provided id.
+ */
+ @Nullable
+ private Byte getPhysicalPort(int displayId) {
if (!mPortLookup.containsKey(displayId)) {
Display display = mDisplayManager.getDisplay(displayId);
if (display == null) {
Log.w(TAG, "Could not retrieve display for id: " + displayId);
- return mDefaultDisplayPhysicalPort;
+ return null;
}
byte port = getPhysicalPort(display);
mPortLookup.put(displayId, port);
@@ -887,6 +900,13 @@
.build();
}
+ private CarUxRestrictions createFullyRestrictedRestrictions() {
+ return new CarUxRestrictions.Builder(
+ /*reqOpt= */ true,
+ CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED,
+ SystemClock.elapsedRealtimeNanos()).build();
+ }
+
CarUxRestrictionsConfiguration createDefaultConfig(byte port) {
return new CarUxRestrictionsConfiguration.Builder()
.setPhysicalPort(port)
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 3956f35..31627b9 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -150,7 +150,7 @@
mAppFocusService, mCarInputService);
mSystemStateControllerService = new SystemStateControllerService(
serviceContext, mCarAudioService, this);
- mVmsBrokerService = new VmsBrokerService();
+ mVmsBrokerService = new VmsBrokerService(mContext.getPackageManager());
mVmsClientManager = new VmsClientManager(
serviceContext, mCarUserService, mUserManagerHelper, mHal.getVmsHal());
mVmsSubscriberService = new VmsSubscriberService(
@@ -169,9 +169,9 @@
CarLocalServices.addService(CarPowerManagementService.class, mCarPowerManagementService);
CarLocalServices.addService(CarUserService.class, mCarUserService);
- CarLocalServices.addService(CarTrustedDeviceService.class,
- mCarTrustedDeviceService);
+ CarLocalServices.addService(CarTrustedDeviceService.class, mCarTrustedDeviceService);
CarLocalServices.addService(SystemInterface.class, mSystemInterface);
+ CarLocalServices.addService(CarDrivingStateService.class, mCarDrivingStateService);
// Be careful with order. Service depending on other service should be inited later.
List<CarServiceBase> allServices = new ArrayList<>();
@@ -449,7 +449,7 @@
+ " without permission " + android.Manifest.permission.DUMP);
return;
}
- if (args == null || args.length == 0) {
+ if (args == null || args.length == 0 || (args.length > 0 && "-a".equals(args[0]))) {
writer.println("*dump car service*");
writer.println("*FutureConfig, DEFAULT:" + FeatureConfiguration.DEFAULT);
@@ -508,6 +508,7 @@
private static final String COMMAND_GARAGE_MODE = "garage-mode";
private static final String COMMAND_GET_DO_ACTIVITIES = "get-do-activities";
private static final String COMMAND_GET_CARPROPERTYCONFIG = "get-carpropertyconfig";
+ private static final String COMMAND_GET_PROPERTY_VALUE = "get-property-value";
private static final String COMMAND_PROJECTION_UI_MODE = "projection-ui-mode";
private static final String COMMAND_RESUME = "resume";
private static final String COMMAND_SUSPEND = "suspend";
@@ -539,6 +540,9 @@
pw.println("\t Get Distraction Optimized activities in given package.");
pw.println("\tget-carpropertyconfig [propertyId]");
pw.println("\t Get a CarPropertyConfig by Id in Hex or list all CarPropertyConfigs");
+ pw.println("\tget-property-value [propertyId] [areaId]");
+ pw.println("\t Get a vehicle property value by property id in Hex and areaId");
+ pw.println("\t or list all property values for all areaId");
pw.println("\tsuspend");
pw.println("\t Suspend the system to Deep Sleep.");
pw.println("\tresume");
@@ -618,6 +622,11 @@
String propertyId = args.length < 2 ? "" : args[1];
mHal.dumpPropertyConfigs(writer, propertyId);
break;
+ case COMMAND_GET_PROPERTY_VALUE:
+ String propId = args.length < 2 ? "" : args[1];
+ String areaId = args.length < 3 ? "" : args[2];
+ mHal.dumpPropertyValueByCommend(writer, propId, areaId);
+ break;
case COMMAND_PROJECTION_UI_MODE:
if (args.length != 2) {
writer.println("Incorrect number of arguments");
@@ -693,19 +702,19 @@
switch (arg) {
case PARAM_ON_MODE:
mGarageModeService.forceStartGarageMode();
+ writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
break;
case PARAM_OFF_MODE:
mGarageModeService.stopAndResetGarageMode();
+ writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
break;
case PARAM_QUERY_MODE:
- // Nothing to do. Always query at the end anyway.
+ mGarageModeService.dump(writer);
break;
default:
writer.println("Unknown value. Valid argument: " + PARAM_ON_MODE + "|"
+ PARAM_OFF_MODE + "|" + PARAM_QUERY_MODE);
- return;
}
- writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
}
/**
diff --git a/service/src/com/android/car/SystemActivityMonitoringService.java b/service/src/com/android/car/SystemActivityMonitoringService.java
index 3894337..d192727 100644
--- a/service/src/com/android/car/SystemActivityMonitoringService.java
+++ b/service/src/com/android/car/SystemActivityMonitoringService.java
@@ -15,6 +15,8 @@
*/
package com.android.car;
+import static com.android.car.pm.CarPackageManagerService.BLOCKING_INTENT_EXTRA_DISPLAY_ID;
+
import android.app.ActivityManager;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityOptions;
@@ -104,7 +106,7 @@
private final HandlerThread mMonitorHandlerThread;
private final ActivityMonitorHandler mHandler;
- /** K: stack id, V: top task */
+ /** K: display id, V: top task */
private final SparseArray<TopTaskInfoContainer> mTopTasks = new SparseArray<>();
/** K: uid, V : list of pid */
private final Map<Integer, Set<Integer>> mForegroundUidPids = new ArrayMap<>();
@@ -377,10 +379,14 @@
* block the current task with the provided new activity.
*/
private void handleBlockActivity(TopTaskInfoContainer currentTask, Intent newActivityIntent) {
- // Only block default display.
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchDisplayId(Display.DEFAULT_DISPLAY);
+ int displayId = newActivityIntent.getIntExtra(BLOCKING_INTENT_EXTRA_DISPLAY_ID,
+ Display.DEFAULT_DISPLAY);
+ if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
+ Log.d(CarLog.TAG_AM, "Launching blocking activity on display: " + displayId);
+ }
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(displayId);
mContext.startActivityAsUser(newActivityIntent, options.toBundle(),
new UserHandle(currentTask.stackInfo.userId));
// Now make stack with new activity focused.
diff --git a/service/src/com/android/car/Utils.java b/service/src/com/android/car/Utils.java
index 1b7c029..2b468b7 100644
--- a/service/src/com/android/car/Utils.java
+++ b/service/src/com/android/car/Utils.java
@@ -15,15 +15,16 @@
*/
package com.android.car;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.util.SparseArray;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.UUID;
@@ -253,4 +254,28 @@
ThreadLocalRandom.current().nextInt((int) Math.pow(10, length)));
}
+
+ /**
+ * Concatentate the given 2 byte arrays
+ *
+ * @param a input array 1
+ * @param b input array 2
+ * @return concatenated array of arrays 1 and 2
+ */
+ @Nullable
+ public static byte[] concatByteArrays(@Nullable byte[] a, @Nullable byte[] b) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ try {
+ if (a != null) {
+ outputStream.write(a);
+ }
+ if (b != null) {
+ outputStream.write(b);
+ }
+ } catch (IOException e) {
+ return null;
+ }
+ return outputStream.toByteArray();
+ }
+
}
diff --git a/service/src/com/android/car/VmsPublisherService.java b/service/src/com/android/car/VmsPublisherService.java
index 0c6ff64..3384e3a 100644
--- a/service/src/com/android/car/VmsPublisherService.java
+++ b/service/src/com/android/car/VmsPublisherService.java
@@ -31,12 +31,16 @@
import com.android.car.vms.VmsBrokerService;
import com.android.car.vms.VmsClientManager;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+
/**
* Receives HAL updates by implementing VmsHalService.VmsHalListener.
* Binds to publishers and configures them to use this service.
@@ -46,12 +50,68 @@
private static final boolean DBG = true;
private static final String TAG = "VmsPublisherService";
+ @VisibleForTesting
+ static final String PACKET_COUNT_FORMAT = "Packet count for layer %s: %d\n";
+
+ @VisibleForTesting
+ static final String PACKET_SIZE_FORMAT = "Total packet size for layer %s: %d (bytes)\n";
+
+ @VisibleForTesting
+ static final String PACKET_FAILURE_COUNT_FORMAT =
+ "Total packet failure count for layer %s from %s to %s: %d\n";
+
+ @VisibleForTesting
+ static final String PACKET_FAILURE_SIZE_FORMAT =
+ "Total packet failure size for layer %s from %s to %s: %d (bytes)\n";
+
private final Context mContext;
private final VmsClientManager mClientManager;
private final VmsBrokerService mBrokerService;
private final Map<String, PublisherProxy> mPublisherProxies = Collections.synchronizedMap(
new ArrayMap<>());
+ @GuardedBy("mPacketCounts")
+ private final Map<VmsLayer, PacketCountAndSize> mPacketCounts = new ArrayMap<>();
+ @GuardedBy("mPacketFailureCounts")
+ private final Map<PacketFailureKey, PacketCountAndSize> mPacketFailureCounts = new ArrayMap<>();
+
+ // PacketCountAndSize keeps track of the cumulative size and number of packets of a specific
+ // VmsLayer that we have seen.
+ private class PacketCountAndSize {
+ long mCount;
+ long mSize;
+ }
+
+ // PacketFailureKey is a triple of the VmsLayer, the publisher and subscriber for which a packet
+ // failed to be sent.
+ private class PacketFailureKey {
+ VmsLayer mVmsLayer;
+ String mPublisher;
+ String mSubscriber;
+
+ PacketFailureKey(VmsLayer vmsLayer, String publisher, String subscriber) {
+ mVmsLayer = vmsLayer;
+ mPublisher = publisher;
+ mSubscriber = subscriber;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof PacketFailureKey)) {
+ return false;
+ }
+
+ PacketFailureKey otherKey = (PacketFailureKey) o;
+ return Objects.equals(mVmsLayer, otherKey.mVmsLayer) && Objects.equals(mPublisher,
+ otherKey.mPublisher) && Objects.equals(mSubscriber, otherKey.mSubscriber);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mVmsLayer, mPublisher, mSubscriber);
+ }
+ }
+
public VmsPublisherService(
Context context,
VmsBrokerService brokerService,
@@ -76,7 +136,29 @@
@Override
public void dump(PrintWriter writer) {
writer.println("*" + getClass().getSimpleName() + "*");
- writer.println("mPublisherProxies:" + mPublisherProxies.keySet());
+ writer.println("mPublisherProxies: " + mPublisherProxies.size());
+ synchronized (mPacketCounts) {
+ for (Map.Entry<VmsLayer, PacketCountAndSize> entry : mPacketCounts.entrySet()) {
+ VmsLayer layer = entry.getKey();
+ PacketCountAndSize countAndSize = entry.getValue();
+ writer.format(PACKET_COUNT_FORMAT, layer, countAndSize.mCount);
+ writer.format(PACKET_SIZE_FORMAT, layer, countAndSize.mSize);
+ }
+ }
+ synchronized (mPacketFailureCounts) {
+ for (Map.Entry<PacketFailureKey, PacketCountAndSize> entry :
+ mPacketFailureCounts.entrySet()) {
+ PacketFailureKey key = entry.getKey();
+ PacketCountAndSize countAndSize = entry.getValue();
+ VmsLayer layer = key.mVmsLayer;
+ String publisher = key.mPublisher;
+ String subscriber = key.mSubscriber;
+ writer.format(PACKET_FAILURE_COUNT_FORMAT, layer, publisher, subscriber,
+ countAndSize.mCount);
+ writer.format(PACKET_FAILURE_SIZE_FORMAT, layer, publisher, subscriber,
+ countAndSize.mSize);
+ }
+ }
}
@Override
@@ -143,6 +225,26 @@
mBrokerService.setPublisherLayersOffering(token, offering);
}
+ private void incrementPacketCount(VmsLayer layer, long size) {
+ synchronized (mPacketCounts) {
+ PacketCountAndSize countAndSize = mPacketCounts.computeIfAbsent(layer,
+ i -> new PacketCountAndSize());
+ countAndSize.mCount++;
+ countAndSize.mSize += size;
+ }
+ }
+
+ private void incrementPacketFailure(VmsLayer layer, String publisher, String subscriber,
+ long size) {
+ synchronized (mPacketFailureCounts) {
+ PacketFailureKey key = new PacketFailureKey(layer, publisher, subscriber);
+ PacketCountAndSize countAndSize = mPacketFailureCounts.computeIfAbsent(key,
+ i -> new PacketCountAndSize());
+ countAndSize.mCount++;
+ countAndSize.mSize += size;
+ }
+ }
+
@Override
public void publish(IBinder token, VmsLayer layer, int publisherId, byte[] payload) {
assertPermission(token);
@@ -150,16 +252,32 @@
Log.d(TAG, String.format("Publishing to %s as %d (%s)", layer, publisherId, mName));
}
+ if (layer == null) {
+ return;
+ }
+
+ int payloadLength = payload != null ? payload.length : 0;
+ incrementPacketCount(layer, payloadLength);
+
// Send the message to subscribers
Set<IVmsSubscriberClient> listeners =
mBrokerService.getSubscribersForLayerFromPublisher(layer, publisherId);
if (DBG) Log.d(TAG, String.format("Number of subscribers: %d", listeners.size()));
+
+ if (listeners.size() == 0) {
+ // An empty string for the last argument is a special value signalizing zero
+ // subscribers for the VMS_PACKET_FAILURE_REPORTED atom.
+ incrementPacketFailure(layer, mName, "", payloadLength);
+ }
+
for (IVmsSubscriberClient listener : listeners) {
try {
listener.onVmsMessageReceived(layer, payload);
} catch (RemoteException ex) {
- Log.e(TAG, String.format("Unable to publish to listener: %s", listener));
+ String subscriberName = mBrokerService.getPackageName(listener);
+ incrementPacketFailure(layer, mName, subscriberName, payloadLength);
+ Log.e(TAG, String.format("Unable to publish to listener: %s", subscriberName));
}
}
}
diff --git a/service/src/com/android/car/VmsSubscriberService.java b/service/src/com/android/car/VmsSubscriberService.java
index fc28978..aaadf4f 100644
--- a/service/src/com/android/car/VmsSubscriberService.java
+++ b/service/src/com/android/car/VmsSubscriberService.java
@@ -200,7 +200,7 @@
VmsHalService hal) {
mContext = context;
mBrokerService = brokerService;
- hal.setVmsSubscriberService(this);
+ hal.setVmsSubscriberService(this, mBrokerService::removeDeadSubscriber);
}
// Implements CarServiceBase interface.
diff --git a/service/src/com/android/car/audio/CarAudioFocus.java b/service/src/com/android/car/audio/CarAudioFocus.java
index 45c2903..165caad 100644
--- a/service/src/com/android/car/audio/CarAudioFocus.java
+++ b/service/src/com/android/car/audio/CarAudioFocus.java
@@ -43,9 +43,10 @@
// Values for the internal interaction matrix we use to make focus decisions
- private static final int INTERACTION_REJECT = 0; // Focus not granted
- private static final int INTERACTION_EXCLUSIVE = 1; // Focus granted, others loose focus
- private static final int INTERACTION_CONCURRENT = 2; // Focus granted, others keep focus
+ static final int INTERACTION_REJECT = 0; // Focus not granted
+ static final int INTERACTION_EXCLUSIVE = 1; // Focus granted, others loose focus
+ static final int INTERACTION_CONCURRENT = 2; // Focus granted, others keep focus
+
// TODO: Make this an overlayable resource...
// MUSIC = 1, // Music playback
@@ -434,6 +435,21 @@
public synchronized void onAudioFocusAbandon(AudioFocusInfo afi) {
Log.i(TAG, "onAudioFocusAbandon " + afi.getClientId());
+ FocusEntry deadEntry = removeFocusEntry(afi);
+
+ if (deadEntry != null) {
+ removeFocusEntryAndRestoreUnblockedWaiters(deadEntry);
+ }
+ }
+
+ /**
+ * Remove Focus entry from focus holder or losers entry lists
+ * @param afi Audio Focus Info to remove
+ * @return Removed Focus Entry
+ */
+ private FocusEntry removeFocusEntry(AudioFocusInfo afi) {
+ Log.i(TAG, "removeFocusEntry " + afi.getClientId());
+
// Remove this entry from our active or pending list
FocusEntry deadEntry = mFocusHolders.remove(afi.getClientId());
if (deadEntry == null) {
@@ -450,11 +466,9 @@
// silently, or else take unexpected action (eg: resume playing spontaneously), or
// else to see "Failure to signal ..." gain/loss error messages in the log from
// this module when a focus change tries to take action on a truly zombie entry.
- return;
}
}
-
- removeFocusEntryAndRestoreUnblockedWaiters(deadEntry);
+ return deadEntry;
}
private void removeFocusEntryAndRestoreUnblockedWaiters(FocusEntry deadEntry) {
@@ -475,32 +489,113 @@
// Add it back into the focus holders list
mFocusHolders.put(entry.getClientId(), entry);
- // Send the focus (re)gain notification
- int result = mAudioManager.dispatchAudioFocusChange(
- entry.mAfi,
- entry.mAfi.getGainRequest(),
- mAudioPolicy);
- if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
- // TODO: Is this actually an error, or is it okay for an entry in the focus
- // stack to NOT have a listener? If that's the case, should we even keep
- // it in the focus stack?
- Log.e(TAG, "Failure to signal gain of audio focus with error: " + result);
- }
+ dispatchFocusGained(entry.mAfi);
+
}
}
}
- public synchronized void dump(PrintWriter writer) {
- writer.println("*CarAudioFocus*");
+ /**
+ * Dispatch focus gain
+ * @param afi Audio focus info
+ * @return AudioManager.AUDIOFOCUS_REQUEST_GRANTED if focus is dispatched successfully
+ */
+ private int dispatchFocusGained(AudioFocusInfo afi) {
+ // Send the focus (re)gain notification
+ int result = mAudioManager.dispatchAudioFocusChange(
+ afi,
+ afi.getGainRequest(),
+ mAudioPolicy);
+ if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ // TODO: Is this actually an error, or is it okay for an entry in the focus
+ // stack to NOT have a listener? If that's the case, should we even keep
+ // it in the focus stack?
+ Log.e(TAG, "Failure to signal gain of audio focus with error: " + result);
+ }
+ return result;
+ }
- writer.println(" Current Focus Holders:");
+
+ /**
+ * Query the current list of focus loser for uid
+ * @param uid uid to query current focus loser
+ * @return list of current focus losers for uid
+ */
+ ArrayList<AudioFocusInfo> getAudioFocusLosersForUid(int uid) {
+ return getAudioFocusListForUid(uid, mFocusLosers);
+ }
+
+ /**
+ * Query the current list of focus holders for uid
+ * @param uid uid to query current focus holders
+ * @return list of current focus holders that for uid
+ */
+ ArrayList<AudioFocusInfo> getAudioFocusHoldersForUid(int uid) {
+ return getAudioFocusListForUid(uid, mFocusHolders);
+ }
+
+ /**
+ * Query input list for matching uid
+ * @param uid uid to match in map
+ * @param mapToQuery map to query for uid info
+ * @return list of audio focus info that match uid
+ */
+ private ArrayList<AudioFocusInfo> getAudioFocusListForUid(int uid,
+ HashMap<String, FocusEntry> mapToQuery) {
+ ArrayList<AudioFocusInfo> matchingInfoList = new ArrayList<>();
+ for (String clientId : mapToQuery.keySet()) {
+ AudioFocusInfo afi = mapToQuery.get(clientId).mAfi;
+ if (afi.getClientUid() == uid) {
+ matchingInfoList.add(afi);
+ }
+ }
+ return matchingInfoList;
+ }
+
+ /**
+ * Remove the audio focus info, if entry is still active
+ * dispatch lose focus transient to listeners
+ * @param afi Audio Focus info to remove
+ */
+ void removeAudioFocusInfoAndTransientlyLoseFocus(AudioFocusInfo afi) {
+ FocusEntry deadEntry = removeFocusEntry(afi);
+
+ if (deadEntry != null) {
+ sendFocusLoss(deadEntry, AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
+ removeFocusEntryAndRestoreUnblockedWaiters(deadEntry);
+ }
+ }
+
+ /**
+ * Reevaluate focus request and regain focus
+ * @param afi audio focus info to reevaluate
+ * @return AudioManager.AUDIOFOCUS_REQUEST_GRANTED if focus is granted
+ */
+ int reevaluateAndRegainAudioFocus(AudioFocusInfo afi) {
+ int results = evaluateFocusRequest(afi);
+
+ if (results == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ return dispatchFocusGained(afi);
+ }
+ return results;
+ }
+
+ /**
+ * dumps the current state of the CarAudioFocus object
+ * @param indent indent to add to each line in the current stream
+ * @param writer stream to write to
+ */
+ public synchronized void dump(String indent, PrintWriter writer) {
+ writer.printf("%s*CarAudioFocus*\n", indent);
+
+ writer.printf("%s\tCurrent Focus Holders:\n", indent);
for (String clientId : mFocusHolders.keySet()) {
- System.out.println(clientId);
+ writer.printf("%s\t\t%s\n", indent, clientId);
}
- writer.println(" Transient Focus Losers:");
+ writer.printf("%s\tTransient Focus Losers:\n", indent);
for (String clientId : mFocusLosers.keySet()) {
- System.out.println(clientId);
+ writer.printf("%s\t\t%s\n", indent, clientId);
}
}
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index 88d3463..62bcd00 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -31,6 +31,7 @@
import android.media.AudioAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioDevicePort;
+import android.media.AudioFocusInfo;
import android.media.AudioFormat;
import android.media.AudioGain;
import android.media.AudioGainConfig;
@@ -65,7 +66,9 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Collectors;
@@ -187,10 +190,14 @@
};
private AudioPolicy mAudioPolicy;
- private CarAudioFocus mFocusHandler;
+ private CarZonesAudioFocus mFocusHandler;
private String mCarAudioConfigurationPath;
private CarAudioZone[] mCarAudioZones;
+ // TODO do not store uid mapping here instead use the uid
+ // device affinity in audio policy when available
+ private Map<Integer, Integer> mUidToZoneMap;
+
public CarAudioService(Context context) {
mContext = context;
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -198,6 +205,7 @@
mUseDynamicRouting = mContext.getResources().getBoolean(R.bool.audioUseDynamicRouting);
mPersistMasterMuteState = mContext.getResources().getBoolean(
R.bool.audioPersistMasterMuteState);
+ mUidToZoneMap = new HashMap<>();
}
/**
@@ -277,7 +285,18 @@
for (CarAudioZone zone : mCarAudioZones) {
zone.dump("\t", writer);
}
+ writer.println();
+ writer.println("\tUID to Zone Mapping:");
+ for (int callingId : mUidToZoneMap.keySet()) {
+ writer.printf("\t\tUID %d mapped to zone %d\n",
+ callingId,
+ mUidToZoneMap.get(callingId));
+ }
+ //Print focus handler info
+ writer.println();
+ mFocusHandler.dump("\t", writer);
}
+
}
@Override
@@ -460,7 +479,9 @@
// Configure our AudioPolicy to handle focus events.
// This gives us the ability to decide which audio focus requests to accept and bypasses
// the framework ducking logic.
- mFocusHandler = new CarAudioFocus(mAudioManager, mContext.getPackageManager());
+ mFocusHandler = new CarZonesAudioFocus(mAudioManager,
+ mContext.getPackageManager(),
+ mCarAudioZones);
builder.setAudioPolicyFocusListener(mFocusHandler);
builder.setIsAudioFocusPolicy(true);
}
@@ -736,6 +757,182 @@
}
}
+ /**
+ * Gets the ids of all available audio zones
+ *
+ * @return Array of available audio zones ids
+ */
+ @Override
+ public @NonNull int[] getAudioZoneIds() {
+ enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+ synchronized (mImplLock) {
+ return Arrays.stream(mCarAudioZones).mapToInt(CarAudioZone::getId).toArray();
+ }
+ }
+
+ /**
+ * Gets the audio zone id currently mapped to uid,
+ * defaults to PRIMARY_AUDIO_ZONE if no mapping exist
+ *
+ * @param uid The uid
+ * @return zone id mapped to uid
+ */
+ @Override
+ public int getZoneIdForUid(int uid) {
+ enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+ synchronized (mImplLock) {
+ if (!mUidToZoneMap.containsKey(uid)) {
+ Log.i(CarLog.TAG_AUDIO, "getZoneIdForUid uid "
+ + uid + " does not have a zone. Defaulting to PRIMARY_AUDIO_ZONE: "
+ + CarAudioManager.PRIMARY_AUDIO_ZONE);
+
+ // Must be added to PRIMARY_AUDIO_ZONE otherwise
+ // audio may be routed to other devices
+ // that match the audio criterion (i.e. usage)
+ setZoneIdForUidNoCheckLocked(CarAudioManager.PRIMARY_AUDIO_ZONE, uid);
+ }
+
+ return mUidToZoneMap.get(uid);
+ }
+ }
+ /**
+ * Maps the audio zone id to uid
+ *
+ * @param zoneId The audio zone id
+ * @param uid The uid to map
+ * @return true if the device affinities, for devices in zone, are successfully set
+ */
+ @Override
+ public boolean setZoneIdForUid(int zoneId, int uid) {
+ enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+ synchronized (mImplLock) {
+ Log.i(CarLog.TAG_AUDIO, "setZoneIdForUid Calling uid "
+ + uid + " mapped to : "
+ + zoneId);
+
+ // Figure out if anything is currently holding focus,
+ // This will change the focus to transient loss while we are switching zones
+ Integer currentZoneId = mUidToZoneMap.get(uid);
+ ArrayList<AudioFocusInfo> currentFocusHoldersForUid = new ArrayList<>();
+ ArrayList<AudioFocusInfo> currentFocusLosersForUid = new ArrayList<>();
+ if (currentZoneId != null) {
+ currentFocusHoldersForUid = mFocusHandler.getAudioFocusHoldersForUid(uid,
+ currentZoneId.intValue());
+ currentFocusLosersForUid = mFocusHandler.getAudioFocusLosersForUid(uid,
+ currentZoneId.intValue());
+ if (!currentFocusHoldersForUid.isEmpty() || !currentFocusLosersForUid.isEmpty()) {
+ // Order matters here: Remove the focus losers first
+ // then do the current holder to prevent loser from popping up while
+ // the focus is being remove for current holders
+ // Remove focus for current focus losers
+ mFocusHandler.transientlyLoseInFocusInZone(currentFocusLosersForUid,
+ currentZoneId.intValue());
+ // Remove focus for current holders
+ mFocusHandler.transientlyLoseInFocusInZone(currentFocusHoldersForUid,
+ currentZoneId.intValue());
+ }
+ }
+
+ // if the current uid is in the list
+ // remove it from the list
+
+ if (checkAndRemoveUidLocked(uid)) {
+ if (setZoneIdForUidNoCheckLocked(zoneId, uid)) {
+ // Order matters here: Regain focus for
+ // Previously lost focus holders then regain
+ // focus for holders that had it last
+ // Regain focus for the focus losers from previous zone
+ if (!currentFocusLosersForUid.isEmpty()) {
+ regainAudioFocusLocked(currentFocusLosersForUid, zoneId);
+ }
+ // Regain focus for the focus holders from previous zone
+ if (!currentFocusHoldersForUid.isEmpty()) {
+ regainAudioFocusLocked(currentFocusHoldersForUid, zoneId);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Regain focus for the focus list passed in
+ * @param afiList focus info list to regain
+ * @param zoneId zone id where the focus holder belong
+ */
+ void regainAudioFocusLocked(ArrayList<AudioFocusInfo> afiList, int zoneId) {
+ for (AudioFocusInfo info : afiList) {
+ if (mFocusHandler.reevaluateAndRegainAudioFocus(info)
+ != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ Log.i(CarLog.TAG_AUDIO,
+ " Focus could not be granted for entry "
+ + info.getClientId()
+ + " uid " + info.getClientUid()
+ + " in zone " + zoneId);
+ }
+ }
+ }
+
+ /**
+ * Removes the current mapping of the uid, focus will be lost in zone
+ * @param uid The uid to remove
+ * return true if all the devices affinities currently
+ * mapped to uid are successfully removed
+ */
+ @Override
+ public boolean clearZoneIdForUid(int uid) {
+ enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+ synchronized (mImplLock) {
+ return checkAndRemoveUidLocked(uid);
+ }
+ }
+
+ /**
+ * Sets the zone id for uid
+ * @param zoneId zone id to map to uid
+ * @param uid uid to map
+ * @return true if setting uid device affinity is successful
+ */
+ private boolean setZoneIdForUidNoCheckLocked(int zoneId, int uid) {
+ Log.d(CarLog.TAG_AUDIO, "setZoneIdForUidNoCheck Calling uid "
+ + uid + " mapped to " + zoneId);
+ //Request to add uid device affinity
+ if (mAudioPolicy.setUidDeviceAffinity(uid, mCarAudioZones[zoneId].getAudioDeviceInfos())) {
+ // TODO do not store uid mapping here instead use the uid
+ // device affinity in audio policy when available
+ mUidToZoneMap.put(uid, zoneId);
+ return true;
+ }
+ Log.w(CarLog.TAG_AUDIO, "setZoneIdForUidNoCheck Failed set device affinity for uid "
+ + uid + " in zone " + zoneId);
+ return false;
+ }
+
+ /**
+ * Check if uid is attached to a zone and remove it
+ * @param uid unique id to remove
+ * @return true if the uid was successfully removed or mapping was not assigned
+ */
+ private boolean checkAndRemoveUidLocked(int uid) {
+ Integer zoneId = mUidToZoneMap.get(uid);
+ if (zoneId != null) {
+ Log.i(CarLog.TAG_AUDIO, "checkAndRemoveUid removing Calling uid "
+ + uid + " from zone " + zoneId);
+ if (mAudioPolicy.removeUidDeviceAffinity(uid)) {
+ // TODO use the uid device affinity in audio policy when available
+ mUidToZoneMap.remove(uid);
+ return true;
+ }
+ //failed to remove device affinity from zone devices
+ Log.w(CarLog.TAG_AUDIO,
+ "checkAndRemoveUid Failed remove device affinity for uid "
+ + uid + " in zone " + zoneId);
+ return false;
+ }
+ return true;
+ }
+
@Override
public void registerVolumeCallback(@NonNull IBinder binder) {
synchronized (mImplLock) {
diff --git a/service/src/com/android/car/audio/CarAudioZone.java b/service/src/com/android/car/audio/CarAudioZone.java
index 36bbf42..4bdf0b7 100644
--- a/service/src/com/android/car/audio/CarAudioZone.java
+++ b/service/src/com/android/car/audio/CarAudioZone.java
@@ -16,6 +16,7 @@
package com.android.car.audio;
import android.car.media.CarAudioManager;
+import android.media.AudioDeviceInfo;
import android.util.Log;
import android.view.DisplayAddress;
@@ -74,6 +75,19 @@
return mVolumeGroups.get(groupId);
}
+ /**
+ * @return Snapshot of available {@link AudioDeviceInfo}s in List.
+ */
+ List<AudioDeviceInfo> getAudioDeviceInfos() {
+ final List<AudioDeviceInfo> devices = new ArrayList<>();
+ for (CarVolumeGroup group : mVolumeGroups) {
+ for (int busNumber : group.getBusNumbers()) {
+ devices.add(group.getCarAudioDeviceInfoForBus(busNumber).getAudioDeviceInfo());
+ }
+ }
+ return devices;
+ }
+
int getVolumeGroupCount() {
return mVolumeGroups.size();
}
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelper.java b/service/src/com/android/car/audio/CarAudioZonesHelper.java
index 00cbb4b..17d9393 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelper.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelper.java
@@ -31,6 +31,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -59,7 +60,6 @@
private static final String ATTR_CONTEXT_NAME = "context";
private static final String ATTR_PHYSICAL_PORT = "port";
private static final int SUPPORTED_VERSION = 1;
- private static final int NO_XML_RESOURCE = 0;
private static final Map<String, Integer> CONTEXT_NAME_MAP;
@@ -93,7 +93,7 @@
mPortIds = new HashSet<>();
}
- public CarAudioZone[] loadAudioZones() throws IOException, XmlPullParserException {
+ CarAudioZone[] loadAudioZones() throws IOException, XmlPullParserException {
List<CarAudioZone> carAudioZones = new ArrayList<>();
parseCarAudioZones(carAudioZones, mInputStream);
return carAudioZones.toArray(new CarAudioZone[0]);
@@ -139,6 +139,7 @@
}
}
Preconditions.checkArgument(mHasPrimaryZone, "Requires one primary zone");
+ carAudioZones.sort(Comparator.comparing(CarAudioZone::getId));
}
private CarAudioZone parseAudioZone(XmlPullParser parser)
@@ -181,7 +182,7 @@
private DisplayAddress.Physical parsePhysicalDisplayAddress(XmlPullParser parser) {
String port = parser.getAttributeValue(NAMESPACE, ATTR_PHYSICAL_PORT);
- Long portId;
+ long portId;
try {
portId = Long.parseLong(port);
} catch (NumberFormatException e) {
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
index b0df7e8..7f11275 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
@@ -74,7 +74,7 @@
}
}
- public CarAudioZone[] loadAudioZones() {
+ CarAudioZone[] loadAudioZones() {
final CarAudioZone zone = new CarAudioZone(CarAudioManager.PRIMARY_AUDIO_ZONE,
"Primary zone");
for (CarVolumeGroup group : loadVolumeGroups()) {
diff --git a/service/src/com/android/car/audio/CarZonesAudioFocus.java b/service/src/com/android/car/audio/CarZonesAudioFocus.java
new file mode 100644
index 0000000..9b4b945
--- /dev/null
+++ b/service/src/com/android/car/audio/CarZonesAudioFocus.java
@@ -0,0 +1,169 @@
+/*
+ * 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.audio;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageManager;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.media.audiopolicy.AudioPolicy;
+import android.util.Log;
+
+import com.android.car.CarLog;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implements {@link AudioPolicy.AudioPolicyFocusListener}
+ *
+ * @note Manages audio focus on a per zone basis.
+ */
+class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
+
+ private CarAudioService mCarAudioService; // Dynamically assigned just after construction
+ private AudioPolicy mAudioPolicy; // Dynamically assigned just after construction
+
+ private final Map<Integer, CarAudioFocus> mFocusZones = new HashMap<>();
+
+ CarZonesAudioFocus(AudioManager audioManager,
+ PackageManager packageManager,
+ @NonNull CarAudioZone[] carAudioZones) {
+ //Create the zones here, the policy will be set setOwningPolicy,
+ // which is called right after this constructor.
+
+ Preconditions.checkNotNull(carAudioZones);
+ Preconditions.checkArgument(carAudioZones.length != 0,
+ "There must be a minimum of one audio zone");
+
+ //Create focus for all the zones
+ for (CarAudioZone audioZone : carAudioZones) {
+ Log.d(CarLog.TAG_AUDIO,
+ "CarZonesAudioFocus adding new zone " + audioZone.getId());
+ CarAudioFocus zoneFocusListener = new CarAudioFocus(audioManager, packageManager);
+ mFocusZones.put(audioZone.getId(), zoneFocusListener);
+ }
+ }
+
+
+ /**
+ * Query the current list of focus loser in zoneId for uid
+ * @param uid uid to query for current focus losers
+ * @param zoneId zone id to query for info
+ * @return list of current focus losers for uid
+ */
+ ArrayList<AudioFocusInfo> getAudioFocusLosersForUid(int uid, int zoneId) {
+ CarAudioFocus focus = mFocusZones.get(zoneId);
+ return focus.getAudioFocusLosersForUid(uid);
+ }
+
+ /**
+ * Query the current list of focus holders in zoneId for uid
+ * @param uid uid to query for current focus holders
+ * @param zoneId zone id to query
+ * @return list of current focus holders that for uid
+ */
+ ArrayList<AudioFocusInfo> getAudioFocusHoldersForUid(int uid, int zoneId) {
+ CarAudioFocus focus = mFocusZones.get(zoneId);
+ return focus.getAudioFocusHoldersForUid(uid);
+ }
+
+ /**
+ * For each entry in list, transiently lose focus
+ * @param afiList list of audio focus entries
+ * @param zoneId zone id where focus should should be lost
+ */
+ void transientlyLoseInFocusInZone(@NonNull ArrayList<AudioFocusInfo> afiList,
+ int zoneId) {
+ CarAudioFocus focus = mFocusZones.get(zoneId);
+
+ for (AudioFocusInfo info : afiList) {
+ focus.removeAudioFocusInfoAndTransientlyLoseFocus(info);
+ }
+ }
+
+ int reevaluateAndRegainAudioFocus(AudioFocusInfo afi) {
+ CarAudioFocus focus = getFocusForUid(afi.getClientUid());
+ return focus.reevaluateAndRegainAudioFocus(afi);
+ }
+
+
+ /**
+ * Sets the owning policy of the audio focus
+ *
+ * @param audioService owning car audio service
+ * @param parentPolicy owning parent car audio policy
+ * @Note This has to happen after the construction to avoid a chicken and egg
+ * problem when setting up the AudioPolicy which must depend on this object.
+ */
+ void setOwningPolicy(CarAudioService audioService, AudioPolicy parentPolicy) {
+ mCarAudioService = audioService;
+ mAudioPolicy = parentPolicy;
+
+ for (int zoneId : mFocusZones.keySet()) {
+ mFocusZones.get(zoneId).setOwningPolicy(mCarAudioService, mAudioPolicy);
+ }
+ }
+
+ @Override
+ public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
+ CarAudioFocus focus = getFocusForUid(afi.getClientUid());
+ focus.onAudioFocusRequest(afi, requestResult);
+ }
+
+ /**
+ * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes)
+ * Note that we'll get this call for a focus holder that dies while in the focus stack, so
+ * we don't need to watch for death notifications directly.
+ */
+ @Override
+ public void onAudioFocusAbandon(AudioFocusInfo afi) {
+ CarAudioFocus focus = getFocusForUid(afi.getClientUid());
+ focus.onAudioFocusAbandon(afi);
+ }
+
+ private CarAudioFocus getFocusForUid(int uid) {
+ //getZoneIdForUid defaults to returning default zoneId
+ //if uid has not been mapped, thus the value returned will be
+ //default zone focus
+ int zoneId = mCarAudioService.getZoneIdForUid(uid);
+
+ CarAudioFocus focus = mFocusZones.get(zoneId);
+ return focus;
+ }
+
+ /**
+ * dumps the current state of the CarZoneAudioFocus
+ *
+ * @param indent indent to append to each new line
+ * @param writer stream to write current state
+ */
+ synchronized void dump(String indent, PrintWriter writer) {
+ writer.printf("%s*CarZonesAudioFocus*\n", indent);
+
+ writer.printf("%s\tCar Zones Audio Focus Listeners:\n", indent);
+ Integer[] keys = mFocusZones.keySet().stream().sorted().toArray(Integer[]::new);
+ for (Integer zoneId : keys) {
+ writer.printf("%s\tZone Id: %s", indent, zoneId.toString());
+ mFocusZones.get(zoneId).dump(indent + "\t", writer);
+ }
+ }
+}
diff --git a/service/src/com/android/car/garagemode/Controller.java b/service/src/com/android/car/garagemode/Controller.java
index 347ba73..d7235dd 100644
--- a/service/src/com/android/car/garagemode/Controller.java
+++ b/service/src/com/android/car/garagemode/Controller.java
@@ -28,6 +28,7 @@
import com.android.car.CarLocalServices;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
@@ -105,6 +106,13 @@
}
/**
+ * @return The names of the jobs that Garage Mode is waiting for
+ */
+ List<String> pendingGarageModeJobs() {
+ return mGarageMode.pendingJobs();
+ }
+
+ /**
* Wrapper method to send a broadcast
*
* @param i intent that contains broadcast data
diff --git a/service/src/com/android/car/garagemode/GarageMode.java b/service/src/com/android/car/garagemode/GarageMode.java
index b13045e..1165de5 100644
--- a/service/src/com/android/car/garagemode/GarageMode.java
+++ b/service/src/com/android/car/garagemode/GarageMode.java
@@ -63,6 +63,7 @@
private boolean mGarageModeActive;
private JobScheduler mJobScheduler;
+ private List<String> mPendingJobs = new ArrayList<>();
private Handler mHandler;
private Runnable mRunnable = new Runnable() {
@Override
@@ -129,6 +130,10 @@
return mGarageModeActive;
}
+ synchronized List<String> pendingJobs() {
+ return mPendingJobs;
+ }
+
void enterGarageMode(CompletableFuture<Void> future) {
LOG.d("Entering GarageMode");
synchronized (this) {
@@ -141,9 +146,7 @@
ArrayList<Integer> startedUsers =
CarLocalServices.getService(CarUserService.class).startAllBackgroundUsers();
synchronized (this) {
- for (Integer user : startedUsers) {
- mStartedBackgroundUsers.add(user);
- }
+ mStartedBackgroundUsers.addAll(startedUsers);
}
}
@@ -224,15 +227,22 @@
mHandler.removeCallbacks(mRunnable);
}
- private int numberOfJobsRunning() {
+ private synchronized int numberOfJobsRunning() {
List<JobInfo> startedJobs = mJobScheduler.getStartedJobs();
int count = 0;
+ List<String> currentPendingJobs = new ArrayList<>();
for (JobSnapshot snap : mJobScheduler.getAllJobSnapshots()) {
if (startedJobs.contains(snap.getJobInfo())
&& snap.getJobInfo().isRequireDeviceIdle()) {
+ currentPendingJobs.add(snap.getJobInfo().toString());
count++;
}
}
+ if (count > 0) {
+ // We have something pending, so update the list.
+ // (Otherwise, keep the old list.)
+ mPendingJobs = currentPendingJobs;
+ }
return count;
}
}
diff --git a/service/src/com/android/car/garagemode/GarageModeService.java b/service/src/com/android/car/garagemode/GarageModeService.java
index f28bb35..8527bc7 100644
--- a/service/src/com/android/car/garagemode/GarageModeService.java
+++ b/service/src/com/android/car/garagemode/GarageModeService.java
@@ -23,6 +23,7 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.util.List;
/**
* Main service container for car Garage Mode.
@@ -63,11 +64,24 @@
/**
* Dumps useful information about GarageMode
- * @param writer
+ * @param writer Where to dump the information
*/
@Override
public void dump(PrintWriter writer) {
- writer.println("GarageModeInProgress " + mController.isGarageModeActive());
+ boolean isActive = mController.isGarageModeActive();
+ writer.println("GarageModeInProgress " + isActive);
+ List<String> jobs = mController.pendingGarageModeJobs();
+ if (isActive) {
+ writer.println("GarageMode is currently waiting for " + jobs.size() + " jobs:");
+ } else {
+ writer.println("GarageMode was last waiting for " + jobs.size() + " jobs:");
+ }
+ // Dump the names of the jobs that GM is/was waiting for
+ int jobNumber = 1;
+ for (String job : jobs) {
+ writer.println(" " + jobNumber + ": " + job);
+ jobNumber++;
+ }
}
/**
diff --git a/service/src/com/android/car/hal/InputHalService.java b/service/src/com/android/car/hal/InputHalService.java
index f0993eb..d719510 100644
--- a/service/src/com/android/car/hal/InputHalService.java
+++ b/service/src/com/android/car/hal/InputHalService.java
@@ -140,12 +140,19 @@
KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
int code = v.value.int32Values.get(1);
int display = v.value.int32Values.get(2);
+ int indentsCount = v.value.int32Values.size() < 4 ? 1 : v.value.int32Values.get(3);
if (DBG) {
- Log.i(CarLog.TAG_INPUT, "hal event code:" + code + ", action:" + action +
- ", display:" + display);
+ Log.i(CarLog.TAG_INPUT, new StringBuilder()
+ .append("hal event code:").append(code)
+ .append(", action:").append(action)
+ .append(", display: ").append(display)
+ .append(", number of indents: ").append(indentsCount)
+ .toString());
}
-
- dispatchKeyEvent(listener, action, code, display);
+ while (indentsCount > 0) {
+ indentsCount--;
+ dispatchKeyEvent(listener, action, code, display);
+ }
}
}
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index 286ca79..d7faa2b 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -485,6 +485,58 @@
}
/**
+ * Dumps vehicle property values.
+ * @param writer
+ * @param propId property id, dump all properties' value if it is empty string.
+ * @param areaId areaId of the property, dump the property for all areaIds in the config
+ * if it is empty string.
+ */
+ public void dumpPropertyValueByCommend(PrintWriter writer, String propId, String areaId) {
+ if (propId.equals("")) {
+ writer.println("**All property values**");
+ for (VehiclePropConfig config : mAllProperties.values()) {
+ dumpPropertyValueByConfig(writer, config);
+ }
+ } else if (areaId.equals("")) {
+ VehiclePropConfig config = mAllProperties.get(Integer.parseInt(propId, 16));
+ dumpPropertyValueByConfig(writer, config);
+ } else {
+ int id = Integer.parseInt(propId, 16);
+ int area = Integer.parseInt(areaId);
+ try {
+ VehiclePropValue value = get(id, area);
+ writer.println(dumpVehiclePropValue(value));
+ } catch (Exception e) {
+ writer.println("Can not get property value for propertyId: 0x"
+ + propId + ", areaId: " + area);
+ }
+ }
+ }
+
+ private void dumpPropertyValueByConfig(PrintWriter writer, VehiclePropConfig config) {
+ if (config.areaConfigs.isEmpty()) {
+ try {
+ VehiclePropValue value = get(config.prop);
+ writer.println(dumpVehiclePropValue(value));
+ } catch (Exception e) {
+ writer.println("Can not get property value for propertyId: 0x"
+ + toHexString(config.prop) + ", areaId: 0");
+ }
+ } else {
+ for (VehicleAreaConfig areaConfig : config.areaConfigs) {
+ int area = areaConfig.areaId;
+ try {
+ VehiclePropValue value = get(config.prop, area);
+ writer.println(dumpVehiclePropValue(value));
+ } catch (Exception e) {
+ writer.println("Can not get property value for propertyId: 0x"
+ + toHexString(config.prop) + ", areaId: " + area);
+ }
+ }
+ }
+ }
+
+ /**
* Dump VHAL property configs.
*
* @param writer
@@ -513,7 +565,7 @@
}
/** Use VehiclePropertyConfig to construct string for dumping */
- private String dumpPropertyConfigsHelp(VehiclePropConfig config) {
+ private static String dumpPropertyConfigsHelp(VehiclePropConfig config) {
StringBuilder builder = new StringBuilder()
.append("Property:0x").append(toHexString(config.prop))
.append(",Property name:").append(VehicleProperty.toString(config.prop))
@@ -640,6 +692,7 @@
StringBuilder sb = new StringBuilder()
.append("Property:0x").append(toHexString(value.prop))
+ .append(",status: ").append(value.status)
.append(",timestamp:").append(value.timestamp)
.append(",zone:0x").append(toHexString(value.areaId))
.append(",floatValues: ").append(Arrays.toString(value.value.floatValues.toArray()))
diff --git a/service/src/com/android/car/hal/VmsHalService.java b/service/src/com/android/car/hal/VmsHalService.java
index 1f6c2e2..3f39f48 100644
--- a/service/src/com/android/car/hal/VmsHalService.java
+++ b/service/src/com/android/car/hal/VmsHalService.java
@@ -40,26 +40,30 @@
import android.hardware.automotive.vehicle.V2_0.VmsMessageWithLayerIntegerValuesIndex;
import android.hardware.automotive.vehicle.V2_0.VmsOfferingMessageIntegerValuesIndex;
import android.hardware.automotive.vehicle.V2_0.VmsPublisherInformationIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_0.VmsStartSessionMessageIntegerValuesIndex;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.ArraySet;
import android.util.Log;
-import androidx.annotation.GuardedBy;
import androidx.annotation.VisibleForTesting;
import com.android.car.CarLog;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* VMS client implementation that proxies VmsPublisher/VmsSubscriber API calls to the Vehicle HAL
@@ -72,18 +76,20 @@
private static final String TAG = "VmsHalService";
private static final int HAL_PROPERTY_ID = VehicleProperty.VEHICLE_MAP_SERVICE;
private static final int NUM_INTEGERS_IN_VMS_LAYER = 3;
+ private static final int UNKNOWN_CLIENT_ID = -1;
private final VehicleHal mVehicleHal;
+ private final int mCoreId;
+ private final MessageQueue mMessageQueue;
private volatile boolean mIsSupported = false;
- private IBinder mPublisherToken;
private IVmsPublisherService mPublisherService;
- private IVmsSubscriberService mSubscriberService;
+ private Consumer<IBinder> mPublisherOnHalConnected;
+ private Runnable mPublisherOnHalDisconnected;
+ private IBinder mPublisherToken;
- @GuardedBy("this")
- private HandlerThread mHandlerThread;
- @GuardedBy("this")
- private Handler mHandler;
+ private IVmsSubscriberService mSubscriberService;
+ private Consumer<IVmsSubscriberClient> mSuscriberOnHalDisconnected;
private int mSubscriptionStateSequence = -1;
private int mAvailableLayersSequence = -1;
@@ -97,14 +103,19 @@
@Override
public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
- // Registration of this callback is handled by VmsPublisherService.
- // As a result, HAL support must be checked whenever the callback is triggered.
- if (!mIsSupported) {
+ if (DBG) Log.d(TAG, "Handling a subscription state change");
+ // Drop out-of-order notifications
+ if (subscriptionState.getSequenceNumber() <= mSubscriptionStateSequence) {
+ Log.w(TAG,
+ String.format("Out of order subscription state received: %d (expecting %d)",
+ subscriptionState.getSequenceNumber(),
+ mSubscriptionStateSequence + 1));
return;
}
- if (DBG) Log.d(TAG, "Handling a subscription state change");
- Message.obtain(mHandler, VmsMessageType.SUBSCRIPTIONS_CHANGE, subscriptionState)
- .sendToTarget();
+ mSubscriptionStateSequence = subscriptionState.getSequenceNumber();
+ mMessageQueue.enqueue(VmsMessageType.SUBSCRIPTIONS_CHANGE,
+ createSubscriptionStateMessage(VmsMessageType.SUBSCRIPTIONS_CHANGE,
+ subscriptionState));
}
};
@@ -112,67 +123,87 @@
@Override
public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
if (DBG) Log.d(TAG, "Handling a data message for Layer: " + layer);
- // TODO(b/124130256): Set publisher ID of data message
- Message.obtain(mHandler, VmsMessageType.DATA, createDataMessage(layer, 0, payload))
- .sendToTarget();
+ mMessageQueue.enqueue(VmsMessageType.DATA, createDataMessage(layer, payload));
}
@Override
public void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers) {
if (DBG) Log.d(TAG, "Handling a layer availability change");
- Message.obtain(mHandler, VmsMessageType.AVAILABILITY_CHANGE, availableLayers)
- .sendToTarget();
+ // Drop out-of-order notifications
+ if (availableLayers.getSequence() <= mAvailableLayersSequence) {
+ Log.w(TAG,
+ String.format("Out of order layer availability received: %d (expecting %d)",
+ availableLayers.getSequence(),
+ mAvailableLayersSequence + 1));
+ return;
+ }
+ mAvailableLayersSequence = availableLayers.getSequence();
+ mMessageQueue.enqueue(VmsMessageType.AVAILABILITY_CHANGE,
+ createAvailableLayersMessage(VmsMessageType.AVAILABILITY_CHANGE,
+ availableLayers));
}
};
- private final Handler.Callback mHandlerCallback = msg -> {
- int messageType = msg.what;
- VehiclePropValue vehicleProp = null;
- switch (messageType) {
- case VmsMessageType.DATA:
- vehicleProp = (VehiclePropValue) msg.obj;
- break;
- case VmsMessageType.SUBSCRIPTIONS_CHANGE:
- VmsSubscriptionState subscriptionState = (VmsSubscriptionState) msg.obj;
- // Drop out-of-order notifications
- if (subscriptionState.getSequenceNumber() <= mSubscriptionStateSequence) {
- break;
- }
- vehicleProp = createSubscriptionStateMessage(
- VmsMessageType.SUBSCRIPTIONS_CHANGE,
- subscriptionState);
- mSubscriptionStateSequence = subscriptionState.getSequenceNumber();
- break;
- case VmsMessageType.AVAILABILITY_CHANGE:
- VmsAvailableLayers availableLayers = (VmsAvailableLayers) msg.obj;
- // Drop out-of-order notifications
- if (availableLayers.getSequence() <= mAvailableLayersSequence) {
- break;
- }
- vehicleProp = createAvailableLayersMessage(
- VmsMessageType.AVAILABILITY_CHANGE,
- availableLayers);
- mAvailableLayersSequence = availableLayers.getSequence();
- break;
- default:
- Log.e(TAG, "Unexpected message type: " + messageType);
+ private class MessageQueue implements Handler.Callback {
+ private final Set<Integer> mSupportedMessageTypes = new ArraySet<>(Arrays.asList(
+ VmsMessageType.DATA,
+ VmsMessageType.START_SESSION,
+ VmsMessageType.AVAILABILITY_CHANGE,
+ VmsMessageType.SUBSCRIPTIONS_CHANGE
+ ));
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
+
+ synchronized void init() {
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper(), this);
}
- if (vehicleProp != null) {
+
+ synchronized void release() {
+ if (mHandlerThread != null) {
+ mHandlerThread.quitSafely();
+ }
+ }
+
+ synchronized void enqueue(int messageType, Object message) {
+ if (mSupportedMessageTypes.contains(messageType)) {
+ Message.obtain(mHandler, messageType, message).sendToTarget();
+ } else {
+ Log.e(TAG, "Unexpected message type: " + VmsMessageType.toString(messageType));
+ }
+ }
+
+ synchronized void clear() {
+ mSupportedMessageTypes.forEach(mHandler::removeMessages);
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ int messageType = msg.what;
+ VehiclePropValue vehicleProp = (VehiclePropValue) msg.obj;
if (DBG) Log.d(TAG, "Sending " + VmsMessageType.toString(messageType) + " message");
try {
setPropertyValue(vehicleProp);
} catch (RemoteException e) {
Log.e(TAG, "While sending " + VmsMessageType.toString(messageType));
}
+ return true;
}
- return true;
- };
+ }
/**
* Constructor used by {@link VehicleHal}
*/
VmsHalService(VehicleHal vehicleHal) {
+ this(vehicleHal, SystemClock::uptimeMillis);
+ }
+
+ @VisibleForTesting
+ VmsHalService(VehicleHal vehicleHal, Supplier<Long> getCoreId) {
mVehicleHal = vehicleHal;
+ mCoreId = (int) (getCoreId.get() % Integer.MAX_VALUE);
+ mMessageQueue = new MessageQueue();
}
/**
@@ -180,21 +211,25 @@
*/
@VisibleForTesting
Handler getHandler() {
- return mHandler;
+ return mMessageQueue.mHandler;
}
/**
* Gets the {@link IVmsPublisherClient} implementation for the HAL's publisher callback.
*/
- public IBinder getPublisherClient() {
- return mPublisherClient.asBinder();
+ public void setPublisherConnectionCallbacks(Consumer<IBinder> onHalConnected,
+ Runnable onHalDisconnected) {
+ mPublisherOnHalConnected = onHalConnected;
+ mPublisherOnHalDisconnected = onHalDisconnected;
}
/**
* Sets a reference to the {@link IVmsSubscriberService} implementation for use by the HAL.
*/
- public void setVmsSubscriberService(IVmsSubscriberService service) {
+ public void setVmsSubscriberService(IVmsSubscriberService service,
+ Consumer<IVmsSubscriberClient> onHalDisconnected) {
mSubscriberService = service;
+ mSuscriberOnHalDisconnected = onHalDisconnected;
}
@Override
@@ -219,39 +254,14 @@
return; // Do not continue initialization
}
- synchronized (this) {
- mHandlerThread = new HandlerThread(TAG);
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
- }
-
- if (mSubscriberService != null) {
- try {
- mSubscriberService.addVmsSubscriberToNotifications(mSubscriberClient);
- } catch (RemoteException e) {
- Log.e(TAG, "While adding subscriber callback", e);
- }
-
- // Publish layer availability to HAL clients (this triggers HAL client initialization)
- try {
- mSubscriberClient.onLayersAvailabilityChanged(
- mSubscriberService.getAvailableLayers());
- } catch (RemoteException e) {
- Log.e(TAG, "While publishing layer availability", e);
- }
- } else if (DBG) {
- Log.d(TAG, "VmsSubscriberService not registered");
- }
+ mMessageQueue.init();
+ mMessageQueue.enqueue(VmsMessageType.START_SESSION,
+ createStartSessionMessage(mCoreId, UNKNOWN_CLIENT_ID));
}
@Override
public void release() {
- synchronized (this) {
- if (mHandlerThread != null) {
- mHandlerThread.quitSafely();
- }
- }
-
+ mMessageQueue.release();
mSubscriptionStateSequence = -1;
mAvailableLayersSequence = -1;
@@ -273,15 +283,15 @@
@Override
public void dump(PrintWriter writer) {
- writer.println(TAG);
- writer.println("VmsProperty " + (mIsSupported ? "" : "not") + " supported.");
+ writer.println("*VMS HAL*");
- writer.println(
- "VmsPublisherService " + (mPublisherService != null ? "" : "not") + " registered.");
+ writer.println("VmsProperty: " + (mIsSupported ? "supported" : "unsupported"));
+ writer.println("VmsPublisherService: "
+ + (mPublisherService != null ? "registered " : "unregistered"));
writer.println("mSubscriptionStateSequence: " + mSubscriptionStateSequence);
- writer.println("VmsSubscriberService " + (mSubscriberService != null ? "" : "not")
- + " registered.");
+ writer.println("VmsSubscriberService: "
+ + (mSubscriberService != null ? "registered" : "unregistered"));
writer.println("mAvailableLayersSequence: " + mAvailableLayersSequence);
}
@@ -330,6 +340,9 @@
case VmsMessageType.SUBSCRIPTIONS_REQUEST:
handleSubscriptionsRequestEvent();
break;
+ case VmsMessageType.START_SESSION:
+ handleStartSessionEvent(vec);
+ break;
default:
Log.e(TAG, "Unexpected message type: " + messageType);
}
@@ -340,6 +353,72 @@
}
/**
+ * SESSION_START message format:
+ * <ul>
+ * <li>Message type
+ * <li>Core ID
+ * <li>Client ID
+ * </ul>
+ */
+ private void handleStartSessionEvent(List<Integer> message) {
+ int coreId = message.get(VmsStartSessionMessageIntegerValuesIndex.SERVICE_ID);
+ int clientId = message.get(VmsStartSessionMessageIntegerValuesIndex.CLIENT_ID);
+ if (DBG) {
+ Log.d(TAG,
+ "Handling a session start event with coreId: " + coreId + " client: "
+ + clientId);
+ }
+
+ if (coreId != mCoreId) {
+ if (mPublisherOnHalDisconnected != null) {
+ mPublisherOnHalDisconnected.run();
+ } else {
+ Log.w(TAG, "Publisher disconnect callback not registered");
+ }
+ if (mSuscriberOnHalDisconnected != null) {
+ mSuscriberOnHalDisconnected.accept(mSubscriberClient);
+ } else {
+ Log.w(TAG, "Subscriber disconnect callback not registered");
+ }
+
+ // Drop all queued messages and client state
+ mMessageQueue.clear();
+ mSubscriptionStateSequence = -1;
+ mAvailableLayersSequence = -1;
+
+ // Enqueue an acknowledgement message
+ mMessageQueue.enqueue(VmsMessageType.START_SESSION,
+ createStartSessionMessage(mCoreId, clientId));
+ }
+
+ // Notify client manager of connection
+ if (mPublisherOnHalConnected != null) {
+ mPublisherOnHalConnected.accept(mPublisherClient);
+ } else {
+ Log.w(TAG, "Publisher connect callback not registered");
+ }
+
+ // Notify subscriber service of connection
+ if (mSubscriberService != null) {
+ try {
+ mSubscriberService.addVmsSubscriberToNotifications(mSubscriberClient);
+ } catch (RemoteException e) {
+ Log.e(TAG, "While adding subscriber callback", e);
+ }
+
+ // Publish layer availability to HAL clients (this triggers HAL client initialization)
+ try {
+ mSubscriberClient.onLayersAvailabilityChanged(
+ mSubscriberService.getAvailableLayers());
+ } catch (RemoteException e) {
+ Log.e(TAG, "While publishing layer availability", e);
+ }
+ } else {
+ Log.w(TAG, "Subscriber connect callback not registered");
+ }
+ }
+
+ /**
* DATA message format:
* <ul>
* <li>Message type
@@ -588,6 +667,30 @@
}
/**
+ * Creates a SESSION_START type {@link VehiclePropValue}.
+ *
+ * SESSION_START message format:
+ * <ul>
+ * <li>Message type
+ * <li>Core ID
+ * <li>Client ID
+ * </ul>
+ */
+ private static VehiclePropValue createStartSessionMessage(int coreId, int clientId) {
+ // Message type + layer
+ VehiclePropValue vehicleProp = createVmsMessage(VmsMessageType.START_SESSION);
+ List<Integer> message = vehicleProp.value.int32Values;
+
+ // Core ID
+ message.add(coreId);
+
+ // Client ID
+ message.add(clientId);
+
+ return vehicleProp;
+ }
+
+ /**
* Creates a DATA type {@link VehiclePropValue}.
*
* DATA message format:
@@ -602,14 +705,15 @@
*
* @param layer Layer for which message was published.
*/
- private static VehiclePropValue createDataMessage(VmsLayer layer, int publisherId,
- byte[] payload) {
+ private static VehiclePropValue createDataMessage(VmsLayer layer, byte[] payload) {
// Message type + layer
- VehiclePropValue vehicleProp = createVmsMessageWithLayer(VmsMessageType.DATA, layer);
+ VehiclePropValue vehicleProp = createVmsMessage(VmsMessageType.DATA);
+ appendLayer(vehicleProp.value.int32Values, layer);
List<Integer> message = vehicleProp.value.int32Values;
// Publisher ID
- message.add(publisherId);
+ // TODO(b/124130256): Set publisher ID of data message
+ message.add(0);
// Payload
appendBytes(vehicleProp.value.bytes, payload);
@@ -709,20 +813,6 @@
}
/**
- * Creates a {@link VehiclePropValue} of the requested message type, with layer message fields
- * populated. Other message fields are *not* populated.
- *
- * @param messageType Type of message, from {@link VmsMessageType}
- * @param layer Layer affected by message.
- */
- private static VehiclePropValue createVmsMessageWithLayer(
- int messageType, VmsLayer layer) {
- VehiclePropValue vehicleProp = createVmsMessage(messageType);
- appendLayer(vehicleProp.value.int32Values, layer);
- return vehicleProp;
- }
-
- /**
* Appends a {@link VmsLayer} to an encoded VMS message.
*
* Layer format:
@@ -761,9 +851,7 @@
message.add(layer.getVmsLayer().getSubtype());
message.add(layer.getVmsLayer().getVersion());
message.add(layer.getPublisherIds().size());
- for (int publisherId : layer.getPublisherIds()) {
- message.add(publisherId);
- }
+ message.addAll(layer.getPublisherIds());
}
private static void appendBytes(ArrayList<Byte> dst, byte[] src) {
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index 7615d28..0f33ff4 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -42,6 +42,7 @@
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -54,7 +55,9 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
+import android.util.SparseArray;
import android.view.Display;
+import android.view.DisplayAddress;
import com.android.car.CarLog;
import com.android.car.CarServiceBase;
@@ -89,6 +92,7 @@
private final SystemActivityMonitoringService mSystemActivityMonitoringService;
private final PackageManager mPackageManager;
private final ActivityManager mActivityManager;
+ private final DisplayManager mDisplayManager;
private final HandlerThread mHandlerThread;
private final PackageHandler mHandler;
@@ -110,7 +114,6 @@
private final HashMap<String, ClientPolicy> mClientPolicies = new HashMap<>();
@GuardedBy("this")
private HashMap<String, AppBlockingPackageInfoWrapper> mActivityWhitelistMap = new HashMap<>();
- // The list corresponding to the one configured in <activityBlacklist>
@GuardedBy("this")
private LinkedList<AppBlockingPolicyProxy> mProxies;
@@ -122,7 +125,10 @@
private final ComponentName mActivityBlockingActivity;
private final ActivityLaunchListener mActivityLaunchListener = new ActivityLaunchListener();
- private final UxRestrictionsListener mUxRestrictionsListener;
+ // K: (logical) display id of a physical display, V: UXR change listener of this display.
+ // For multi-display, monitor UXR change on each display.
+ private final SparseArray<UxRestrictionsListener> mUxRestrictionsListeners =
+ new SparseArray<>();
private final VendorServiceController mVendorServiceController;
// Information related to when the installed packages should be parsed for building a white and
@@ -171,6 +177,12 @@
*/
public static final String BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO = "is_root_activity_do";
+ /**
+ * int display id of the blocked task.
+ * @hide
+ */
+ public static final String BLOCKING_INTENT_EXTRA_DISPLAY_ID = "display_id";
+
public CarPackageManagerService(Context context,
CarUxRestrictionsManagerService uxRestrictionsService,
SystemActivityMonitoringService systemActivityMonitoringService,
@@ -180,7 +192,7 @@
mSystemActivityMonitoringService = systemActivityMonitoringService;
mPackageManager = mContext.getPackageManager();
mActivityManager = mContext.getSystemService(ActivityManager.class);
- mUxRestrictionsListener = new UxRestrictionsListener(uxRestrictionsService);
+ mDisplayManager = mContext.getSystemService(DisplayManager.class);
mHandlerThread = new HandlerThread(CarLog.TAG_PACKAGE);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
@@ -281,14 +293,14 @@
@Override
public boolean isActivityBackedBySafeActivity(ComponentName activityName) {
- if (!mUxRestrictionsListener.isRestricted()) {
- return true;
- }
StackInfo info = mSystemActivityMonitoringService.getFocusedStackForTopActivity(
activityName);
if (info == null) { // not top in focused stack
return true;
}
+ if (!isUxRestrictedOnDisplay(info.displayId)) {
+ return true;
+ }
if (info.taskNames.length <= 1) { // nothing below this.
return false;
}
@@ -385,8 +397,11 @@
}
mContext.unregisterReceiver(mPackageParsingEventReceiver);
mContext.unregisterReceiver(mUserSwitchedEventReceiver);
- mCarUxRestrictionsService.unregisterUxRestrictionsChangeListener(mUxRestrictionsListener);
mSystemActivityMonitoringService.registerActivityLaunchListener(null);
+ for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
+ UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i);
+ mCarUxRestrictionsService.unregisterUxRestrictionsChangeListener(listener);
+ }
}
// run from HandlerThread
@@ -402,15 +417,22 @@
pkgParseIntent.addDataScheme("package");
mContext.registerReceiverAsUser(mPackageParsingEventReceiver, UserHandle.ALL,
pkgParseIntent, null, null);
- try {
- // TODO(128456985): register listener for each display in order to
- // properly launch blocking screens.
- mCarUxRestrictionsService.registerUxRestrictionsChangeListener(
- mUxRestrictionsListener, Display.DEFAULT_DISPLAY);
- } catch (IllegalArgumentException e) {
- // can happen while mocking is going on while init is still done.
- Log.w(CarLog.TAG_PACKAGE, "sensor subscription failed", e);
- return;
+
+ List<Display> physicalDisplays = getPhysicalDisplays();
+
+ // Assume default display (display 0) is always a physical display.
+ Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ if (!physicalDisplays.contains(defaultDisplay)) {
+ if (Log.isLoggable(CarLog.TAG_PACKAGE, Log.INFO)) {
+ Log.i(CarLog.TAG_PACKAGE, "Adding default display to physical displays.");
+ }
+ physicalDisplays.add(defaultDisplay);
+ }
+ for (Display physicalDisplay : physicalDisplays) {
+ int displayId = physicalDisplay.getDisplayId();
+ UxRestrictionsListener listener = new UxRestrictionsListener(mCarUxRestrictionsService);
+ mUxRestrictionsListeners.put(displayId, listener);
+ mCarUxRestrictionsService.registerUxRestrictionsChangeListener(listener, displayId);
}
mSystemActivityMonitoringService.registerActivityLaunchListener(
mActivityLaunchListener);
@@ -423,7 +445,7 @@
synchronized (this) {
mHasParsedPackages = true;
}
- mUxRestrictionsListener.checkIfTopActivityNeedsBlocking();
+ blockTopActivitiesIfNecessary();
}
private synchronized void doHandleRelease() {
@@ -901,7 +923,14 @@
writer.println("*PackageManagementService*");
writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking);
writer.println("mHasParsedPackages:" + mHasParsedPackages);
- writer.println("ActivityRestricted:" + mUxRestrictionsListener.isRestricted());
+ List<String> restrictions = new ArrayList<>(mUxRestrictionsListeners.size());
+ for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
+ int displayId = mUxRestrictionsListeners.keyAt(i);
+ UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i);
+ restrictions.add(String.format("Display %d is %s",
+ displayId, (listener.isRestricted() ? "restricted" : "unrestricted")));
+ }
+ writer.println("Display Restrictions:\n" + String.join("\n", restrictions));
writer.println(String.join("\n", mBlockedActivityLogs));
writer.print(dumpPoliciesLocked(true));
}
@@ -946,15 +975,55 @@
return sb.toString();
}
+ /**
+ * Returns display with physical address.
+ */
+ private List<Display> getPhysicalDisplays() {
+ List<Display> displays = new ArrayList<>();
+ for (Display display : mDisplayManager.getDisplays()) {
+ if (display.getAddress() instanceof DisplayAddress.Physical) {
+ displays.add(display);
+ }
+ }
+ return displays;
+ }
+
+ /**
+ * Returns whether UX restrictions is required for display.
+ *
+ * Non-physical display will use restrictions for {@link Display#DEFAULT_DISPLAY}.
+ */
+ private boolean isUxRestrictedOnDisplay(int displayId) {
+ UxRestrictionsListener listenerForTopTaskDisplay;
+ if (mUxRestrictionsListeners.indexOfKey(displayId) < 0) {
+ listenerForTopTaskDisplay = mUxRestrictionsListeners.get(Display.DEFAULT_DISPLAY);
+ if (listenerForTopTaskDisplay == null) {
+ // This should never happen.
+ Log.e(CarLog.TAG_PACKAGE, "Missing listener for default display.");
+ return true;
+ }
+ } else {
+ listenerForTopTaskDisplay = mUxRestrictionsListeners.get(displayId);
+ }
+
+ return listenerForTopTaskDisplay.isRestricted();
+ }
+
+ private void blockTopActivitiesIfNecessary() {
+ List<TopTaskInfoContainer> topTasks = mSystemActivityMonitoringService.getTopTasks();
+ for (TopTaskInfoContainer topTask : topTasks) {
+ if (topTask == null) {
+ Log.e(CarLog.TAG_PACKAGE, "Top tasks contains null.");
+ continue;
+ }
+ blockTopActivityIfNecessary(topTask);
+ }
+ }
+
private void blockTopActivityIfNecessary(TopTaskInfoContainer topTask) {
- // Only block activities launched on default display.
- if (topTask.displayId != Display.DEFAULT_DISPLAY) {
- return;
+ if (isUxRestrictedOnDisplay(topTask.displayId)) {
+ doBlockTopActivityIfNotAllowed(topTask);
}
- if (!mUxRestrictionsListener.isRestricted()) {
- return;
- }
- doBlockTopActivityIfNotAllowed(topTask);
}
private void doBlockTopActivityIfNotAllowed(TopTaskInfoContainer topTask) {
@@ -1004,8 +1073,9 @@
}
Intent newActivityIntent = createBlockingActivityIntent(
- mActivityBlockingActivity, topTask.topActivity.flattenToShortString(),
- topTask.taskId, taskRootActivity, isRootDO);
+ mActivityBlockingActivity, topTask.displayId,
+ topTask.topActivity.flattenToShortString(), topTask.taskId, taskRootActivity,
+ isRootDO);
// Intent contains all info to debug what is blocked - log into both logcat and dumpsys.
String log = "Starting blocking activity with intent: " + newActivityIntent.toUri(0);
@@ -1027,10 +1097,14 @@
* @return an intent to launch the blocking activity.
*/
private static Intent createBlockingActivityIntent(ComponentName blockingActivity,
- String blockedActivity, int blockedTaskId, String taskRootActivity, boolean isRootDo) {
+ int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity,
+ boolean isRootDo) {
Intent newActivityIntent = new Intent();
+ newActivityIntent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
newActivityIntent.setComponent(blockingActivity);
newActivityIntent.putExtra(
+ BLOCKING_INTENT_EXTRA_DISPLAY_ID, displayId);
+ newActivityIntent.putExtra(
BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME, blockedActivity);
newActivityIntent.putExtra(
BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID, blockedTaskId);
@@ -1042,21 +1116,6 @@
return newActivityIntent;
}
- private void blockTopActivitiesIfNecessary() {
- boolean restricted = mUxRestrictionsListener.isRestricted();
- if (!restricted) {
- return;
- }
- List<TopTaskInfoContainer> topTasks = mSystemActivityMonitoringService.getTopTasks();
- for (TopTaskInfoContainer topTask : topTasks) {
- if (topTask == null) {
- Log.e(CarLog.TAG_PACKAGE, "Top tasks contains null.");
- continue;
- }
- doBlockTopActivityIfNotAllowed(topTask);
- }
- }
-
/**
* Enable/Disable activity blocking by correspondingly enabling/disabling broadcasting UXR
* changes in {@link CarUxRestrictionsManagerService}. This is only available in
@@ -1327,9 +1386,10 @@
}
}
if (DBG_POLICY_ENFORCEMENT) {
- Log.d(CarLog.TAG_PACKAGE, "block?: " + shouldCheck);
+ Log.d(CarLog.TAG_PACKAGE, "Should check top tasks?: " + shouldCheck);
}
if (shouldCheck) {
+ // Loop over all top tasks to ensure tasks on virtual display can also be blocked.
blockTopActivitiesIfNecessary();
}
}
diff --git a/service/src/com/android/car/storagemonitoring/SysfsLifetimeWriteInfoProvider.java b/service/src/com/android/car/storagemonitoring/SysfsLifetimeWriteInfoProvider.java
index 50cc57c..6ba3163 100644
--- a/service/src/com/android/car/storagemonitoring/SysfsLifetimeWriteInfoProvider.java
+++ b/service/src/com/android/car/storagemonitoring/SysfsLifetimeWriteInfoProvider.java
@@ -19,7 +19,9 @@
import android.annotation.Nullable;
import android.car.storagemonitoring.LifetimeWriteInfo;
import android.util.Log;
+
import com.android.internal.annotations.VisibleForTesting;
+
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@@ -100,7 +102,12 @@
for (String fstype : KNOWN_FILESYSTEMS) {
File fspath = new File(mWriteInfosPath, fstype);
if (!fspath.exists() || !fspath.isDirectory()) continue;
- Arrays.stream(fspath.listFiles(File::isDirectory))
+ File[] files = fspath.listFiles(File::isDirectory);
+ if (files == null) {
+ Log.e(TAG, "there are no directories at location " + fspath.getAbsolutePath());
+ continue;
+ }
+ Arrays.stream(files)
.map(this::tryParse)
.filter(Objects::nonNull)
.forEach(writeInfos::add);
diff --git a/service/src/com/android/car/trust/BLEMessagePayloadStream.java b/service/src/com/android/car/trust/BLEMessagePayloadStream.java
index 1f1fdb1..75345b8 100644
--- a/service/src/com/android/car/trust/BLEMessagePayloadStream.java
+++ b/service/src/com/android/car/trust/BLEMessagePayloadStream.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.util.Log;
-import com.android.car.trust.BLEStream.BLEMessage;
+import com.android.car.BLEStreamProtos.BLEMessageProto.BLEMessage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
diff --git a/service/src/com/android/car/trust/BLEMessageV1Factory.java b/service/src/com/android/car/trust/BLEMessageV1Factory.java
index c0b11d4..2478eca 100644
--- a/service/src/com/android/car/trust/BLEMessageV1Factory.java
+++ b/service/src/com/android/car/trust/BLEMessageV1Factory.java
@@ -18,9 +18,9 @@
import android.util.Log;
-import com.android.car.trust.BLEStream.BLEMessage;
-import com.android.car.trust.BLEStream.BLEMessage.OperationType;
-import com.android.car.trust.protobuf.ByteString;
+import com.android.car.BLEStreamProtos.BLEMessageProto.BLEMessage;
+import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
+import com.android.car.protobuf.ByteString;
import java.util.ArrayList;
import java.util.Arrays;
@@ -88,8 +88,7 @@
+ (FIXED_32_SIZE + FIELD_NUMBER_ENCODING_SIZE)
+ (FIXED_32_SIZE + FIELD_NUMBER_ENCODING_SIZE);
- private BLEMessageV1Factory() {
- }
+ private BLEMessageV1Factory() {}
/**
* Method used to generate a single message, the packet number and total packets will set to 1
diff --git a/service/src/com/android/car/trust/BleManager.java b/service/src/com/android/car/trust/BleManager.java
index 61e1be6..28a8fee 100644
--- a/service/src/com/android/car/trust/BleManager.java
+++ b/service/src/com/android/car/trust/BleManager.java
@@ -22,6 +22,7 @@
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
@@ -54,6 +55,9 @@
private static final int BLE_RETRY_LIMIT = 5;
private static final int BLE_RETRY_INTERVAL_MS = 1000;
+ private static final int GATT_SERVER_RETRY_LIMIT = 20;
+ private static final int GATT_SERVER_RETRY_DELAY_MS = 200;
+
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth
// .service.generic_access.xml
private static final UUID GENERIC_ACCESS_PROFILE_UUID =
@@ -71,6 +75,10 @@
private BluetoothGattServer mGattServer;
private BluetoothGatt mBluetoothGatt;
private int mAdvertiserStartCount;
+ private int mGattServerRetryStartCount;
+ private BluetoothGattService mBluetoothGattService;
+ private AdvertiseCallback mAdvertiseCallback;
+ private AdvertiseData mData;
BleManager(Context context) {
mContext = context;
@@ -97,32 +105,38 @@
return;
}
+ mBluetoothGattService = service;
+ mAdvertiseCallback = advertiseCallback;
+ mData = data;
+ mGattServerRetryStartCount = 0;
+ mBluetoothManager = (BluetoothManager) mContext.getSystemService(
+ Context.BLUETOOTH_SERVICE);
+ openGattServer();
+ }
+
+ private void openGattServer() {
// Only open one Gatt server.
- if (mGattServer == null) {
+ if (mGattServer != null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Opening a new GATT Server");
+ Log.d(TAG, "Gatt Server created, retry count: " + mGattServerRetryStartCount);
}
- mBluetoothManager = (BluetoothManager) mContext.getSystemService(
- Context.BLUETOOTH_SERVICE);
- mGattServer = mBluetoothManager.openGattServer(mContext, mGattServerCallback);
-
- if (mGattServer == null) {
- Log.e(TAG, "Gatt Server not created");
- return;
- }
- }
-
- mGattServer.clearServices();
- mGattServer.addService(service);
-
- AdvertiseSettings settings = new AdvertiseSettings.Builder()
+ mGattServer.clearServices();
+ mGattServer.addService(mBluetoothGattService);
+ AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
.setConnectable(true)
.build();
-
- mAdvertiserStartCount = 0;
- startAdvertisingInternally(settings, data, advertiseCallback);
+ mAdvertiserStartCount = 0;
+ startAdvertisingInternally(settings, mData, mAdvertiseCallback);
+ mGattServerRetryStartCount = 0;
+ } else if (mGattServerRetryStartCount < GATT_SERVER_RETRY_LIMIT) {
+ mGattServer = mBluetoothManager.openGattServer(mContext, mGattServerCallback);
+ mGattServerRetryStartCount++;
+ mHandler.postDelayed(() -> openGattServer(), GATT_SERVER_RETRY_DELAY_MS);
+ } else {
+ Log.e(TAG, "Gatt server not created - exceeded retry limit.");
+ }
}
private void startAdvertisingInternally(AdvertiseSettings settings, AdvertiseData data,
@@ -132,6 +146,9 @@
}
if (mAdvertiser != null) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Advertiser created, retry count: " + mAdvertiserStartCount);
+ }
mAdvertiser.startAdvertising(settings, data, advertiseCallback);
mAdvertiserStartCount = 0;
} else if (mAdvertiserStartCount < BLE_RETRY_LIMIT) {
@@ -160,8 +177,14 @@
*/
protected void notifyCharacteristicChanged(BluetoothDevice device,
BluetoothGattCharacteristic characteristic, boolean confirm) {
- if (mGattServer != null) {
- mGattServer.notifyCharacteristicChanged(device, characteristic, confirm);
+ if (mGattServer == null) {
+ return;
+ }
+
+ boolean result = mGattServer.notifyCharacteristicChanged(device, characteristic, confirm);
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "notifyCharacteristicChanged succeeded: " + result);
}
}
@@ -209,6 +232,9 @@
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "stopGattServer");
}
+ if (mBluetoothGatt != null) {
+ mBluetoothGatt.disconnect();
+ }
mGattServer.close();
mGattServer = null;
}
@@ -325,6 +351,19 @@
}
@Override
+ public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
+ BluetoothGattDescriptor descriptor, boolean preparedWrite,
+ boolean responseNeeded, int offset, byte[] value) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Write request for descriptor: " + descriptor.getUuid()
+ + "; value: " + Utils.byteArrayToHexString(value));
+ }
+
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
+ offset, value);
+ }
+
+ @Override
public void onMtuChanged(BluetoothDevice device, int mtu) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onMtuChanged: " + mtu + " for device " + device.getAddress());
diff --git a/service/src/com/android/car/trust/CarBleTrustAgent.java b/service/src/com/android/car/trust/CarBleTrustAgent.java
index 772afdb..08035b8 100644
--- a/service/src/com/android/car/trust/CarBleTrustAgent.java
+++ b/service/src/com/android/car/trust/CarBleTrustAgent.java
@@ -134,9 +134,6 @@
mCarTrustAgentUnlockService.stopUnlockAdvertising();
}
- // Set the trust state to false (not trusted), so unlocking is required for current user
- // in case of user switch.
- revokeTrust();
}
@Override
diff --git a/service/src/com/android/car/trust/CarTrustAgentBleManager.java b/service/src/com/android/car/trust/CarTrustAgentBleManager.java
index c47f527..718bd22 100644
--- a/service/src/com/android/car/trust/CarTrustAgentBleManager.java
+++ b/service/src/com/android/car/trust/CarTrustAgentBleManager.java
@@ -20,6 +20,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
@@ -30,12 +31,14 @@
import androidx.annotation.Nullable;
+import com.android.car.BLEStreamProtos.BLEMessageProto.BLEMessage;
+import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
+import com.android.car.BLEStreamProtos.VersionExchangeProto.BLEVersionExchange;
import com.android.car.CarLocalServices;
import com.android.car.R;
import com.android.car.Utils;
-import com.android.car.trust.BLEStream.BLEMessage;
-import com.android.car.trust.BLEStream.BLEMessage.OperationType;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
@@ -51,6 +54,16 @@
private static final String TAG = "CarTrustBLEManager";
+ /**
+ * The UUID of the Client Characteristic Configuration Descriptor. This descriptor is
+ * responsible for specifying if a characteristic can be subscribed to for notifications.
+ *
+ * @see <a href="https://www.bluetooth.com/specifications/gatt/descriptors/">
+ * GATT Descriptors</a>
+ */
+ private static final UUID CLIENT_CHARACTERISTIC_CONFIG =
+ UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
+
/** @hide */
@IntDef(prefix = {"TRUSTED_DEVICE_OPERATION_"}, value = {
TRUSTED_DEVICE_OPERATION_NONE,
@@ -83,11 +96,15 @@
// Unlock Service and Characteristic UUIDs
private UUID mUnlockServiceUuid;
- private UUID mUnlockEscrowTokenUuid;
- private UUID mUnlockTokenHandleUuid;
+ private UUID mUnlockClientWriteUuid;
+ private UUID mUnlockServerWriteUuid;
private BluetoothGattService mUnlockGattService;
private BLEMessagePayloadStream mBleMessagePayloadStream = new BLEMessagePayloadStream();
+ // This is a boolean because there's only one supported version.
+ private boolean mIsVersionExchanged;
+ private static final int MESSAGING_VERSION = 1;
+ private static final int SECURITY_VERSION = 1;
CarTrustAgentBleManager(Context context) {
super(context);
@@ -105,6 +122,11 @@
&& device.getName() == null) {
retrieveDeviceName(device);
}
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Reset mIsVersionExchanged to false.");
+ }
+ mIsVersionExchanged = false;
getTrustedDeviceService().onRemoteDeviceConnected(device);
}
@@ -113,6 +135,10 @@
if (getTrustedDeviceService() != null) {
getTrustedDeviceService().onRemoteDeviceDisconnected(device);
}
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Reset mIsVersionExchanged to false.");
+ }
+ mIsVersionExchanged = false;
}
@Override
@@ -135,27 +161,37 @@
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onCharacteristicWrite received uuid: " + uuid);
}
+ if (!mIsVersionExchanged) {
+ if (uuid.equals(mEnrollmentClientWriteUuid)) {
+ resolveBLEVersion(device, value, mEnrollmentGattService
+ .getCharacteristic(mEnrollmentServerWriteUuid));
+ } else if (uuid.equals(mUnlockClientWriteUuid)) {
+ resolveBLEVersion(device, value, mUnlockGattService
+ .getCharacteristic(mUnlockServerWriteUuid));
+ } else {
+ Log.e(TAG, "Invalid UUID, disconnect remote device.");
+ disconnectRemoteDevice();
+ }
+ return;
+ }
// This write operation is not thread safe individually, but is guarded by the callback
// here.
mBleMessagePayloadStream.write(value);
if (!mBleMessagePayloadStream.isComplete()) {
return;
}
+
if (uuid.equals(mEnrollmentClientWriteUuid)) {
if (getEnrollmentService() != null) {
getEnrollmentService().onEnrollmentDataReceived(
mBleMessagePayloadStream.toByteArray());
}
- } else if (uuid.equals(mUnlockEscrowTokenUuid)) {
+ } else if (uuid.equals(mUnlockClientWriteUuid)) {
if (getUnlockService() != null) {
- getUnlockService().onUnlockTokenReceived(mBleMessagePayloadStream.toByteArray());
-
- }
- } else if (uuid.equals(mUnlockTokenHandleUuid)) {
- if (getUnlockService() != null) {
- getUnlockService().onUnlockHandleReceived(mBleMessagePayloadStream.toByteArray());
+ getUnlockService().onUnlockDataReceived(mBleMessagePayloadStream.toByteArray());
}
}
+
mBleMessagePayloadStream.reset();
}
@@ -222,10 +258,48 @@
return mRandomName;
}
+ private void resolveBLEVersion(BluetoothDevice device, byte[] value,
+ BluetoothGattCharacteristic characteristic) {
+ BLEVersionExchange versionExchange;
+ try {
+ versionExchange = BLEVersionExchange.parseFrom(value);
+ } catch (IOException e) {
+ disconnectRemoteDevice();
+ Log.e(TAG, "Could not parse version exchange message", e);
+ return;
+ }
+ int minMessagingVersion = versionExchange.getMinSupportedMessagingVersion();
+ int minSecurityVersion = versionExchange.getMinSupportedSecurityVersion();
+ // The supported versions for the communication and security protocol.
+ // Only v1 is supported at this time.
+ // TODO:(b/134094617) get supported versions from BleMessageFactory
+ if (minMessagingVersion != MESSAGING_VERSION || minSecurityVersion != SECURITY_VERSION) {
+ Log.e(TAG, "No supported version (minMessagingVersion: " + minMessagingVersion
+ + ", minSecurityVersion" + minSecurityVersion + ")");
+ disconnectRemoteDevice();
+ return;
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Resolved version to (minMessagingVersion: " + minMessagingVersion
+ + ", minSecurityVersion" + minSecurityVersion + ")");
+ }
+ BLEVersionExchange headUnitVersion = BLEVersionExchange.newBuilder()
+ .setMinSupportedMessagingVersion(MESSAGING_VERSION)
+ .setMaxSupportedMessagingVersion(MESSAGING_VERSION)
+ .setMinSupportedSecurityVersion(SECURITY_VERSION)
+ .setMinSupportedSecurityVersion(SECURITY_VERSION)
+ .build();
+ setValueOnCharacteristicAndNotify(device, headUnitVersion.toByteArray(), characteristic);
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Sent supported versioned to the phone.");
+ }
+ mIsVersionExchanged = true;
+ }
+
/**
* Setup the BLE GATT server for Enrollment. The GATT server for Enrollment comprises of one
- * GATT Service and 2 characteristics - one for the escrow token to be generated and sent from
- * the phone and the other for the handle generated and sent by the Head unit.
+ * GATT Service and 2 characteristics - one for the phone to write to and one for the head unit
+ * to write to.
*/
void setupEnrollmentBleServer() {
mEnrollmentServiceUuid = UUID.fromString(
@@ -238,18 +312,20 @@
mEnrollmentGattService = new BluetoothGattService(mEnrollmentServiceUuid,
BluetoothGattService.SERVICE_TYPE_PRIMARY);
- // Characteristic to describe the escrow token being used for unlock
+ // Characteristic the connected bluetooth device will write to.
BluetoothGattCharacteristic clientCharacteristic =
new BluetoothGattCharacteristic(mEnrollmentClientWriteUuid,
BluetoothGattCharacteristic.PROPERTY_WRITE,
BluetoothGattCharacteristic.PERMISSION_WRITE);
- // Characteristic to describe the handle being used for this escrow token
+ // Characteristic that this manager will write to.
BluetoothGattCharacteristic serverCharacteristic =
new BluetoothGattCharacteristic(mEnrollmentServerWriteUuid,
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ);
+ addDescriptorToCharacteristic(serverCharacteristic);
+
mEnrollmentGattService.addCharacteristic(clientCharacteristic);
mEnrollmentGattService.addCharacteristic(serverCharacteristic);
}
@@ -257,32 +333,42 @@
/**
* Setup the BLE GATT server for Unlocking the Head unit. The GATT server for this phase also
* comprises of 1 Service and 2 characteristics. However both the token and the handle are sent
- * ftrom the phone to the head unit.
+ * from the phone to the head unit.
*/
void setupUnlockBleServer() {
mUnlockServiceUuid = UUID.fromString(getContext().getString(R.string.unlock_service_uuid));
- mUnlockEscrowTokenUuid = UUID
- .fromString(getContext().getString(R.string.unlock_escrow_token_uuid));
- mUnlockTokenHandleUuid = UUID
- .fromString(getContext().getString(R.string.unlock_handle_uuid));
+ mUnlockClientWriteUuid = UUID
+ .fromString(getContext().getString(R.string.unlock_client_write_uuid));
+ mUnlockServerWriteUuid = UUID
+ .fromString(getContext().getString(R.string.unlock_server_write_uuid));
mUnlockGattService = new BluetoothGattService(mUnlockServiceUuid,
BluetoothGattService.SERVICE_TYPE_PRIMARY);
- // Characteristic to describe the escrow token being used for unlock
- BluetoothGattCharacteristic tokenCharacteristic = new BluetoothGattCharacteristic(
- mUnlockEscrowTokenUuid,
+ // Characteristic the connected bluetooth device will write to.
+ BluetoothGattCharacteristic clientCharacteristic = new BluetoothGattCharacteristic(
+ mUnlockClientWriteUuid,
BluetoothGattCharacteristic.PROPERTY_WRITE,
BluetoothGattCharacteristic.PERMISSION_WRITE);
- // Characteristic to describe the handle being used for this escrow token
- BluetoothGattCharacteristic handleCharacteristic = new BluetoothGattCharacteristic(
- mUnlockTokenHandleUuid,
- BluetoothGattCharacteristic.PROPERTY_WRITE,
- BluetoothGattCharacteristic.PERMISSION_WRITE);
+ // Characteristic that this manager will write to.
+ BluetoothGattCharacteristic serverCharacteristic = new BluetoothGattCharacteristic(
+ mUnlockServerWriteUuid,
+ BluetoothGattCharacteristic.PROPERTY_NOTIFY,
+ BluetoothGattCharacteristic.PERMISSION_READ);
- mUnlockGattService.addCharacteristic(tokenCharacteristic);
- mUnlockGattService.addCharacteristic(handleCharacteristic);
+ addDescriptorToCharacteristic(serverCharacteristic);
+
+ mUnlockGattService.addCharacteristic(clientCharacteristic);
+ mUnlockGattService.addCharacteristic(serverCharacteristic);
+ }
+
+ private void addDescriptorToCharacteristic(BluetoothGattCharacteristic characteristic) {
+ BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(
+ CLIENT_CHARACTERISTIC_CONFIG,
+ BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE);
+ descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
+ characteristic.addDescriptor(descriptor);
}
void startEnrollmentAdvertising() {
@@ -340,31 +426,58 @@
stopGattServer();
}
- /**
- * Sends the given message to the specified device.
- *
- * @param device The device to send the message to.
- * @param message A message to send.
- */
- void sendMessage(BluetoothDevice device, byte[] message, OperationType operation,
+ void sendUnlockMessage(BluetoothDevice device, byte[] message, OperationType operation,
boolean isPayloadEncrypted) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "sendMessage to: " + device.getAddress());
- }
- BluetoothGattCharacteristic serverCharacteristic = mEnrollmentGattService
+ BluetoothGattCharacteristic writeCharacteristic = mUnlockGattService
+ .getCharacteristic(mUnlockServerWriteUuid);
+
+ sendMessage(device, writeCharacteristic, message, operation, isPayloadEncrypted);
+ }
+
+ void sendEnrollmentMessage(BluetoothDevice device, byte[] message, OperationType operation,
+ boolean isPayloadEncrypted) {
+ BluetoothGattCharacteristic writeCharacteristic = mEnrollmentGattService
.getCharacteristic(mEnrollmentServerWriteUuid);
+
+ sendMessage(device, writeCharacteristic, message, operation, isPayloadEncrypted);
+ }
+
+ /**
+ * Sends the given message to the specified device and characteristic.
+ * The message will be splited into multiple messages wrapped in BLEMessage proto.
+ *
+ * @param device The device to send the message to.
+ * @param characteristic The characteristic to write to.
+ * @param message A message to send.
+ * @param operation The type of operation this message represents.
+ * @param isPayloadEncrypted {@code true} if the message is encrypted.
+ */
+ private void sendMessage(BluetoothDevice device, BluetoothGattCharacteristic characteristic,
+ byte[] message, OperationType operation, boolean isPayloadEncrypted) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "sendMessage to: " + device.getAddress() + "; and characteristic UUID: "
+ + characteristic.getUuid());
+ }
+
List<BLEMessage> bleMessages = BLEMessageV1Factory.makeBLEMessages(message, operation,
mMtuSize, isPayloadEncrypted);
+
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "sending " + bleMessages.size() + " messages to device");
}
+
for (BLEMessage bleMessage : bleMessages) {
// TODO(b/131719066) get acknowledgement from the phone then continue to send packets
- serverCharacteristic.setValue(bleMessage.toByteArray());
- notifyCharacteristicChanged(device, serverCharacteristic, false);
+ setValueOnCharacteristicAndNotify(device, bleMessage.toByteArray(), characteristic);
}
}
+ void setValueOnCharacteristicAndNotify(BluetoothDevice device, byte[] message,
+ BluetoothGattCharacteristic characteristic) {
+ characteristic.setValue(message);
+ notifyCharacteristicChanged(device, characteristic, false);
+ }
+
private final AdvertiseCallback mEnrollmentAdvertisingCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
@@ -401,6 +514,9 @@
public void onStartFailure(int errorCode) {
Log.e(TAG, "Failed to advertise, errorCode: " + errorCode);
super.onStartFailure(errorCode);
+ if (errorCode == AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED) {
+ return;
+ }
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Start unlock advertising fail, retry to advertising..");
}
diff --git a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
index 39ec796..6d99def 100644
--- a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
+++ b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
@@ -16,8 +16,12 @@
package com.android.car.trust;
+import static android.car.trust.CarTrustAgentEnrollmentManager.ENROLLMENT_HANDSHAKE_FAILURE;
import static android.car.trust.CarTrustAgentEnrollmentManager.ENROLLMENT_NOT_ALLOWED;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.bluetooth.BluetoothDevice;
import android.car.encryptionrunner.EncryptionRunner;
@@ -36,14 +40,11 @@
import android.os.RemoteException;
import android.util.Log;
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
+import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
import com.android.car.R;
import com.android.car.Utils;
-import com.android.car.trust.BLEStream.BLEMessage.OperationType;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -70,7 +71,8 @@
private static final String TAG = "CarTrustAgentEnroll";
private static final String TRUSTED_DEVICE_ENROLLMENT_ENABLED_KEY =
"trusted_device_enrollment_enabled";
- private static final byte[] CONFIRMATION_SIGNAL = "True".getBytes();
+ @VisibleForTesting
+ static final byte[] CONFIRMATION_SIGNAL = "True".getBytes();
//Arbirary log size
private static final int MAX_LOG_SIZE = 20;
@@ -95,25 +97,27 @@
private EncryptionRunner mEncryptionRunner = EncryptionRunnerFactory.newRunner();
private HandshakeMessage mHandshakeMessage;
private Key mEncryptionKey;
+ @VisibleForTesting
@HandshakeState
- private int mEncryptionState = HandshakeState.UNKNOWN;
-
+ int mEncryptionState = HandshakeState.UNKNOWN;
// State of last message sent to phone in enrollment process. Order matters with
// state being auto-incremented.
- private static final int ENROLLMENT_STATE_NONE = 0;
- private static final int ENROLLMENT_STATE_UNIQUE_ID = 1;
- private static final int ENROLLMENT_STATE_ENCRYPTION_COMPLETED = 2;
- private static final int ENROLLMENT_STATE_HANDLE = 3;
+ static final int ENROLLMENT_STATE_NONE = 0;
+ static final int ENROLLMENT_STATE_UNIQUE_ID = 1;
+ static final int ENROLLMENT_STATE_ENCRYPTION_COMPLETED = 2;
+ static final int ENROLLMENT_STATE_HANDLE = 3;
/** @hide */
+ @VisibleForTesting
@Retention(RetentionPolicy.SOURCE)
@IntDef({ENROLLMENT_STATE_NONE, ENROLLMENT_STATE_UNIQUE_ID,
ENROLLMENT_STATE_ENCRYPTION_COMPLETED, ENROLLMENT_STATE_HANDLE})
- public @interface EnrollmentState {
+ @interface EnrollmentState {
}
+ @VisibleForTesting
@EnrollmentState
- private int mEnrollmentState;
+ int mEnrollmentState;
public CarTrustAgentEnrollmentService(Context context, CarTrustedDeviceService service,
CarTrustAgentBleManager bleService) {
@@ -126,6 +130,14 @@
mCarTrustAgentBleManager.setupEnrollmentBleServer();
}
+ /**
+ * Pass a dummy encryption to generate a dummy key, only for test purpose.
+ */
+ @VisibleForTesting
+ void setEncryptionRunner(EncryptionRunner dummyEncryptionRunner) {
+ mEncryptionRunner = dummyEncryptionRunner;
+ }
+
public synchronized void release() {
for (EnrollmentStateClient client : mEnrollmentStateClients) {
client.mListenerBinder.unlinkToDeath(client, 0);
@@ -134,7 +146,6 @@
client.mListenerBinder.unlinkToDeath(client, 0);
}
mEnrollmentStateClients.clear();
- setEnrollmentHandshakeAccepted(false);
}
// Implementing the ICarTrustAgentEnrollment interface
@@ -148,13 +159,7 @@
if (!mTrustedDeviceService.getSharedPrefs()
.getBoolean(TRUSTED_DEVICE_ENROLLMENT_ENABLED_KEY, true)) {
Log.e(TAG, "Trusted Device Enrollment disabled");
- for (EnrollmentStateClient client : mEnrollmentStateClients) {
- try {
- client.mListener.onEnrollmentHandshakeFailure(null, ENROLLMENT_NOT_ALLOWED);
- } catch (RemoteException e) {
- Log.e(TAG, "onEnrollmentHandshakeFailure dispatch failed", e);
- }
- }
+ dispatchEnrollmentFailure(ENROLLMENT_NOT_ALLOWED);
return;
}
// Stop any current broadcasts
@@ -189,9 +194,16 @@
@Override
public void enrollmentHandshakeAccepted(BluetoothDevice device) {
addEnrollmentServiceLog("enrollmentHandshakeAccepted");
- mCarTrustAgentBleManager.sendMessage(device, CONFIRMATION_SIGNAL,
+ if (device == null || !device.equals(mRemoteEnrollmentDevice)) {
+ Log.wtf(TAG,
+ "Enrollment Failure: device is different from cached remote bluetooth device,"
+ + " disconnect from the device. current device is:" + device);
+ mCarTrustAgentBleManager.disconnectRemoteDevice();
+ return;
+ }
+ mCarTrustAgentBleManager.sendEnrollmentMessage(mRemoteEnrollmentDevice, CONFIRMATION_SIGNAL,
OperationType.ENCRYPTION_HANDSHAKE, /* isPayloadEncrypted= */ false);
- setEnrollmentHandshakeAccepted(true);
+ setEnrollmentHandshakeAccepted();
}
/**
@@ -201,7 +213,6 @@
*/
@Override
public void terminateEnrollmentHandshake() {
- setEnrollmentHandshakeAccepted(false);
addEnrollmentServiceLog("terminateEnrollmentHandshake");
// Disconnect from BLE
mCarTrustAgentBleManager.disconnectRemoteDevice();
@@ -269,7 +280,10 @@
public void setTrustedDeviceEnrollmentEnabled(boolean isEnabled) {
SharedPreferences.Editor editor = mTrustedDeviceService.getSharedPrefs().edit();
editor.putBoolean(TRUSTED_DEVICE_ENROLLMENT_ENABLED_KEY, isEnabled);
- editor.apply();
+ if (!editor.commit()) {
+ Log.wtf(TAG,
+ "Enrollment Failure: Commit to SharedPreferences failed. Enable? " + isEnabled);
+ }
}
/**
@@ -332,6 +346,14 @@
}
}
+
+ /**
+ * Called after the escrow token has been successfully added to the framework.
+ *
+ * @param token the escrow token which has been added
+ * @param handle the given handle of that token
+ * @param uid the current user id
+ */
void onEscrowTokenAdded(byte[] token, long handle, int uid) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onEscrowTokenAdded handle:" + handle + " uid:" + uid);
@@ -340,10 +362,10 @@
if (mRemoteEnrollmentDevice == null) {
Log.e(TAG, "onEscrowTokenAdded() but no remote device connected!");
removeEscrowToken(handle, uid);
+ dispatchEnrollmentFailure(ENROLLMENT_HANDSHAKE_FAILURE);
return;
}
- // To conveniently get the user id to unlock when handle is received.
- mTrustedDeviceService.getSharedPrefs().edit().putInt(String.valueOf(handle), uid).apply();
+
mTokenActiveStateMap.put(handle, false);
for (EnrollmentStateClient client : mEnrollmentStateClients) {
try {
@@ -354,6 +376,10 @@
}
}
+
+ /**
+ * Called after the escrow token has been successfully removed from the framework.
+ */
void onEscrowTokenRemoved(long handle, int uid) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onEscrowTokenRemoved handle:" + handle + " uid:" + uid);
@@ -372,14 +398,18 @@
Iterator<String> iterator = deviceInfos.iterator();
while (iterator.hasNext()) {
String deviceInfoString = iterator.next();
- if (TrustedDeviceInfo.deserialize(deviceInfoString).getHandle()
- == handle) {
+ if (TrustedDeviceInfo.deserialize(deviceInfoString).getHandle() == handle) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Removing trusted device handle: " + handle);
+ }
iterator.remove();
break;
}
}
editor.putStringSet(String.valueOf(uid), deviceInfos);
- editor.apply();
+ if (!editor.commit()) {
+ Log.e(TAG, "EscrowToken removed, but shared prefs update failed");
+ }
}
/**
@@ -391,36 +421,68 @@
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onEscrowTokenActiveStateChanged: " + Long.toHexString(handle));
}
+ if (mRemoteEnrollmentDevice == null || !isTokenActive) {
+ if (mRemoteEnrollmentDevice == null) {
+ Log.e(TAG,
+ "Device disconnected before sending back handle. Enrollment incomplete");
+ }
+ if (!isTokenActive) {
+ Log.e(TAG, "Unexpected: Escrow Token activation failed");
+ }
+ removeEscrowToken(handle, uid);
+ dispatchEnrollmentFailure(ENROLLMENT_HANDSHAKE_FAILURE);
+ return;
+ }
+
mTokenActiveStateMap.put(handle, isTokenActive);
- dispatchEscrowTokenActiveStateChanged(handle, isTokenActive);
- if (isTokenActive) {
- Set<String> deviceInfo = mTrustedDeviceService.getSharedPrefs().getStringSet(
- String.valueOf(uid), new HashSet<>());
- String deviceName;
- if (mRemoteEnrollmentDevice.getName() != null) {
- deviceName = mRemoteEnrollmentDevice.getName();
- } else if (mDeviceName != null) {
- deviceName = mDeviceName;
- } else {
- deviceName = mContext.getString(R.string.trust_device_default_name);
- }
- addEnrollmentServiceLog("trustedDeviceAdded (handle:" + handle + ", uid:" + uid
- + ", addr:" + mRemoteEnrollmentDevice.getAddress()
- + ", name:" + deviceName + ")");
- deviceInfo.add(new TrustedDeviceInfo(handle, mRemoteEnrollmentDevice.getAddress(),
- deviceName).serialize());
- // To conveniently get the devices info regarding certain user.
- mTrustedDeviceService.getSharedPrefs().edit().putStringSet(String.valueOf(uid),
- deviceInfo).apply();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Sending handle: " + handle);
- }
- mCarTrustAgentBleManager.sendMessage(mRemoteEnrollmentDevice,
+ Set<String> deviceInfo = mTrustedDeviceService.getSharedPrefs().getStringSet(
+ String.valueOf(uid), new HashSet<>());
+ String deviceName;
+ if (mRemoteEnrollmentDevice.getName() != null) {
+ deviceName = mRemoteEnrollmentDevice.getName();
+ } else if (mDeviceName != null) {
+ deviceName = mDeviceName;
+ mCarTrustAgentBleManager.sendEnrollmentMessage(mRemoteEnrollmentDevice,
mEncryptionKey.encryptData(Utils.longToBytes(handle)),
OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */ true);
} else {
- removeEscrowToken(handle, uid);
+ deviceName = mContext.getString(R.string.trust_device_default_name);
}
+ StringBuffer log = new StringBuffer()
+ .append("trustedDeviceAdded (handle:").append(handle)
+ .append(", uid:").append(uid)
+ .append(", addr:").append(mRemoteEnrollmentDevice.getAddress())
+ .append(", name:").append(deviceName).append(")");
+ addEnrollmentServiceLog(log.toString());
+ deviceInfo.add(new TrustedDeviceInfo(handle, mRemoteEnrollmentDevice.getAddress(),
+ deviceName).serialize());
+
+ // To conveniently get the devices info regarding certain user.
+ SharedPreferences.Editor editor = mTrustedDeviceService.getSharedPrefs().edit();
+ editor.putStringSet(String.valueOf(uid), deviceInfo);
+ if (!editor.commit()) {
+ Log.e(TAG, "Writing DeviceInfo to shared prefs Failed");
+ removeEscrowToken(handle, uid);
+ dispatchEnrollmentFailure(ENROLLMENT_HANDSHAKE_FAILURE);
+ return;
+ }
+
+ // To conveniently get the user id to unlock when handle is received.
+ editor.putInt(String.valueOf(handle), uid);
+ if (!editor.commit()) {
+ Log.e(TAG, "Writing (handle, uid) to shared prefs Failed");
+ removeEscrowToken(handle, uid);
+ dispatchEnrollmentFailure(ENROLLMENT_HANDSHAKE_FAILURE);
+ return;
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Sending handle: " + handle);
+ }
+ mCarTrustAgentBleManager.sendEnrollmentMessage(mRemoteEnrollmentDevice,
+ mEncryptionKey.encryptData(Utils.longToBytes(handle)),
+ OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */ true);
+ dispatchEscrowTokenActiveStateChanged(handle, isTokenActive);
}
void onEnrollmentAdvertiseStartSuccess() {
@@ -443,10 +505,14 @@
}
}
+ /**
+ * Called when a device has been connected through bluetooth
+ *
+ * @param device the connected device
+ */
void onRemoteDeviceConnected(BluetoothDevice device) {
- resetEncryptionState();
-
addEnrollmentServiceLog("onRemoteDeviceConnected (addr:" + device.getAddress() + ")");
+ resetEncryptionState();
synchronized (mRemoteDeviceLock) {
mRemoteEnrollmentDevice = device;
}
@@ -454,15 +520,21 @@
try {
client.mListener.onBleEnrollmentDeviceConnected(device);
} catch (RemoteException e) {
- Log.e(TAG, "onAdvertiseSuccess dispatch failed", e);
+ Log.e(TAG, "onRemoteDeviceConnected dispatch failed", e);
}
}
+ mCarTrustAgentBleManager.stopEnrollmentAdvertising();
}
void onRemoteDeviceDisconnected(BluetoothDevice device) {
- resetEncryptionState();
-
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Device Disconnected: " + device.getAddress() + " Enrollment State: "
+ + mEnrollmentState + " Encryption State: " + mEncryptionState);
+ }
addEnrollmentServiceLog("onRemoteDeviceDisconnected (addr:" + device.getAddress() + ")");
+ addEnrollmentServiceLog(
+ "Enrollment State: " + mEnrollmentState + " EncryptionState: " + mEncryptionState);
+ resetEncryptionState();
synchronized (mRemoteDeviceLock) {
mRemoteEnrollmentDevice = null;
}
@@ -470,11 +542,16 @@
try {
client.mListener.onBleEnrollmentDeviceDisconnected(device);
} catch (RemoteException e) {
- Log.e(TAG, "onAdvertiseSuccess dispatch failed", e);
+ Log.e(TAG, "onRemoteDeviceDisconnected dispatch failed", e);
}
}
}
+ /**
+ * Called when data is received during enrollment process.
+ *
+ * @param value received data
+ */
void onEnrollmentDataReceived(byte[] value) {
if (mEnrollmentDelegate == null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -497,7 +574,7 @@
notifyEscrowTokenReceived(value);
break;
case ENROLLMENT_STATE_HANDLE:
- // TODO(danharms): React to ACK. Shut down server?
+ mCarTrustAgentBleManager.disconnectRemoteDevice();
break;
default:
// Should never get here
@@ -520,11 +597,18 @@
Log.d(TAG, "Received device id: " + mDeviceId);
}
UUID uniqueId = mTrustedDeviceService.getUniqueId();
+ if (uniqueId == null) {
+ Log.e(TAG, "Cannot get Unique ID for the IHU");
+ resetEnrollmentStateOnFailure();
+ dispatchEnrollmentFailure(ENROLLMENT_HANDSHAKE_FAILURE);
+ return;
+ }
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Sending device id: " + uniqueId.toString());
}
- mCarTrustAgentBleManager.sendMessage(mRemoteEnrollmentDevice, Utils.uuidToBytes(uniqueId),
- OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */ false);
+ mCarTrustAgentBleManager.sendEnrollmentMessage(mRemoteEnrollmentDevice,
+ Utils.uuidToBytes(uniqueId), OperationType.CLIENT_MESSAGE,
+ /* isPayloadEncrypted= */ false);
mEnrollmentState++;
}
@@ -559,7 +643,7 @@
mHandshakeMessage = mEncryptionRunner.respondToInitRequest(message);
mEncryptionState = mHandshakeMessage.getHandshakeState();
- mCarTrustAgentBleManager.sendMessage(
+ mCarTrustAgentBleManager.sendEnrollmentMessage(
mRemoteEnrollmentDevice, mHandshakeMessage.getNextMessage(),
OperationType.ENCRYPTION_HANDSHAKE, /* isPayloadEncrypted= */ false);
@@ -586,7 +670,7 @@
showVerificationCode();
return;
}
- mCarTrustAgentBleManager.sendMessage(mRemoteEnrollmentDevice,
+ mCarTrustAgentBleManager.sendEnrollmentMessage(mRemoteEnrollmentDevice,
mHandshakeMessage.getNextMessage(), OperationType.ENCRYPTION_HANDSHAKE,
/* isPayloadEncrypted= */ false);
break;
@@ -627,36 +711,44 @@
}
/**
+ * Reset the whole enrollment state. Disconnects the peer device and removes any escrow token
+ * that has not been activated.
+ *
+ * <p>This method should be called from any stage in the middle of enrollment where we
+ * encounter a failure.
+ */
+ private void resetEnrollmentStateOnFailure() {
+ terminateEnrollmentHandshake();
+ resetEncryptionState();
+ }
+
+ /**
* Resets the encryption status of this service.
*
* <p>This method should be called each time a device connects so that a new handshake can be
* started and encryption keys exchanged.
*/
private void resetEncryptionState() {
- setEnrollmentHandshakeAccepted(false);
-
mEncryptionRunner = EncryptionRunnerFactory.newRunner();
mHandshakeMessage = null;
mEncryptionKey = null;
mEncryptionState = HandshakeState.UNKNOWN;
+ mEnrollmentState = ENROLLMENT_STATE_NONE;
}
- private synchronized void setEnrollmentHandshakeAccepted(boolean accepted) {
- if (!accepted) {
- return;
- }
-
+ private synchronized void setEnrollmentHandshakeAccepted() {
if (mEncryptionRunner == null) {
Log.e(TAG, "Received notification that enrollment handshake was accepted, "
+ "but encryption was never set up.");
return;
}
-
HandshakeMessage message;
try {
message = mEncryptionRunner.verifyPin();
} catch (HandshakeException e) {
Log.e(TAG, "Error during PIN verification", e);
+ resetEnrollmentStateOnFailure();
+ dispatchEnrollmentFailure(ENROLLMENT_HANDSHAKE_FAILURE);
return;
}
@@ -668,9 +760,12 @@
mEncryptionState = HandshakeState.FINISHED;
mEncryptionKey = message.getKey();
- mTrustedDeviceService.saveEncryptionKey(mDeviceId, mEncryptionKey.asBytes());
+ if (!mTrustedDeviceService.saveEncryptionKey(mDeviceId, mEncryptionKey.asBytes())) {
+ resetEnrollmentStateOnFailure();
+ dispatchEnrollmentFailure(ENROLLMENT_HANDSHAKE_FAILURE);
+ return;
+ }
mEnrollmentState++;
-
}
/**
@@ -842,6 +937,16 @@
}
}
+ private void dispatchEnrollmentFailure(int error) {
+ for (EnrollmentStateClient client : mEnrollmentStateClients) {
+ try {
+ client.mListener.onEnrollmentHandshakeFailure(null, error);
+ } catch (RemoteException e) {
+ Log.e(TAG, "onEnrollmentHandshakeFailure dispatch failed", e);
+ }
+ }
+ }
+
/**
* Class that holds onto client related information - listener interface, process that hosts the
* binder object etc.
diff --git a/service/src/com/android/car/trust/CarTrustAgentUnlockService.java b/service/src/com/android/car/trust/CarTrustAgentUnlockService.java
index e8a0afd..57d8e2c 100644
--- a/service/src/com/android/car/trust/CarTrustAgentUnlockService.java
+++ b/service/src/com/android/car/trust/CarTrustAgentUnlockService.java
@@ -16,31 +16,109 @@
package com.android.car.trust;
+import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.bluetooth.BluetoothDevice;
+import android.car.encryptionrunner.EncryptionRunner;
+import android.car.encryptionrunner.EncryptionRunnerFactory;
+import android.car.encryptionrunner.HandshakeException;
+import android.car.encryptionrunner.HandshakeMessage;
+import android.car.encryptionrunner.Key;
import android.content.SharedPreferences;
import android.util.Log;
+import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
import com.android.car.Utils;
import com.android.internal.annotations.GuardedBy;
+import com.google.security.cryptauth.lib.securegcm.D2DConnectionContext;
+import com.google.security.cryptauth.lib.securemessage.CryptoOps;
+
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;
import java.util.Queue;
+import java.util.UUID;
+
+import javax.crypto.spec.SecretKeySpec;
/**
* A service that interacts with the Trust Agent {@link CarBleTrustAgent} and a comms (BLE) service
* {@link CarTrustAgentBleManager} to receive the necessary credentials to authenticate
* an Android user.
+ *
+ * <p>
+ * The unlock flow is as follows:
+ * <ol>
+ * <li>IHU advertises via BLE when it is in a locked state. The advertisement includes its
+ * identifier.
+ * <li>Phone (Trusted device) scans, finds and connects to the IHU.
+ * <li>Protocol versions are exchanged and verified.
+ * <li>Phone sends its identifier in plain text.
+ * <li>IHU verifies that the phone is enrolled as a trusted device from its identifier.
+ * <li>IHU, then sends an ACK back to the phone.
+ * <li>Phone & IHU go over the key exchange (using UKEY2) for encrypting this new session.
+ * <li>Key exchange is completed without any numeric comparison.
+ * <li>Phone sends its MAC (digest) that is computed from the context from this new session and the
+ * previous session.
+ * <li>IHU computes Phone's MAC and validates against what the phone sent. On validation failure,
+ * the stored encryption keys for the phone are deleted. This would require the phone to re-enroll
+ * again.
+ * <li>IHU sends its MAC that is computed similarly from the new session and previous session
+ * contexts.
+ * <li>Phone computes IHU's MAC internally and validates it against what it received.
+ * <li>At this point, the devices have mutually authenticated each other and also have keys to
+ * encrypt
+ * current session.
+ * <li>IHU saves the current session keys. This would serve for authenticating the next session.
+ * <li>Phone sends the encrypted escrow token and handle to the IHU.
+ * <li>IHU retrieves the user id and authenticates the user.
+ * </ol>
*/
public class CarTrustAgentUnlockService {
private static final String TAG = "CarTrustAgentUnlock";
private static final String TRUSTED_DEVICE_UNLOCK_ENABLED_KEY = "trusted_device_unlock_enabled";
- //Arbirary log size
+
+ // Arbitrary log size
private static final int MAX_LOG_SIZE = 20;
+ private static final byte[] RESUME = "RESUME".getBytes();
+ private static final byte[] SERVER = "SERVER".getBytes();
+ private static final byte[] CLIENT = "CLIENT".getBytes();
+ private static final int RESUME_HMAC_LENGTH = 32;
+
+ private static final byte[] ACKNOWLEDGEMENT_MESSAGE = "ACK".getBytes();
+
+ // State of the unlock process. Important to maintain the same order in both phone and IHU.
+ // State increments to the next state on successful completion.
+ private static final int UNLOCK_STATE_WAITING_FOR_UNIQUE_ID = 0;
+ private static final int UNLOCK_STATE_KEY_EXCHANGE_IN_PROGRESS = 1;
+ private static final int UNLOCK_STATE_WAITING_FOR_CLIENT_AUTH = 2;
+ private static final int UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED = 3;
+ private static final int UNLOCK_STATE_TOKEN_RECEIVED = 4;
+ private static final int UNLOCK_STATE_HANDLE_RECEIVED = 5;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"UNLOCK_STATE_"}, value = {UNLOCK_STATE_WAITING_FOR_UNIQUE_ID,
+ UNLOCK_STATE_KEY_EXCHANGE_IN_PROGRESS, UNLOCK_STATE_WAITING_FOR_CLIENT_AUTH,
+ UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED, UNLOCK_STATE_TOKEN_RECEIVED,
+ UNLOCK_STATE_HANDLE_RECEIVED})
+ @interface UnlockState {
+ }
+
+ @UnlockState
+ private int mCurrentUnlockState = UNLOCK_STATE_WAITING_FOR_UNIQUE_ID;
+
private final CarTrustedDeviceService mTrustedDeviceService;
private final CarTrustAgentBleManager mCarTrustAgentBleManager;
private CarTrustAgentUnlockDelegate mUnlockDelegate;
+ private String mClientDeviceId;
private final Queue<String> mLogQueue = new LinkedList<>();
+
// Locks
private final Object mTokenLock = new Object();
private final Object mHandleLock = new Object();
@@ -50,9 +128,19 @@
private byte[] mUnlockToken;
@GuardedBy("mHandleLock")
private byte[] mUnlockHandle;
+
@GuardedBy("mDeviceLock")
private BluetoothDevice mRemoteUnlockDevice;
+ private EncryptionRunner mEncryptionRunner = EncryptionRunnerFactory.newRunner();
+ private HandshakeMessage mHandshakeMessage;
+ private Key mEncryptionKey;
+ @HandshakeMessage.HandshakeState
+ private int mEncryptionState = HandshakeMessage.HandshakeState.UNKNOWN;
+
+ private D2DConnectionContext mPrevContext;
+ private D2DConnectionContext mCurrentContext;
+
CarTrustAgentUnlockService(CarTrustedDeviceService service,
CarTrustAgentBleManager bleService) {
mTrustedDeviceService = service;
@@ -78,13 +166,17 @@
* Enable or disable authentication of the head unit with a trusted device.
*
* @param isEnabled when set to {@code false}, head unit will not be
- * discoverable to unlock the user. Setting it to {@code true} will enable it back.
+ * discoverable to unlock the user. Setting it to {@code true} will enable it
+ * back.
*/
public void setTrustedDeviceUnlockEnabled(boolean isEnabled) {
SharedPreferences.Editor editor = mTrustedDeviceService.getSharedPrefs().edit();
editor.putBoolean(TRUSTED_DEVICE_UNLOCK_ENABLED_KEY, isEnabled);
- editor.apply();
+ if (!editor.commit()) {
+ Log.wtf(TAG, "Unlock Enable Failed. Enable? " + isEnabled);
+ }
}
+
/**
* Set a delegate that implements {@link CarTrustAgentUnlockDelegate}. The delegate will be
* handed the auth related data (token and handle) when it is received from the remote
@@ -127,6 +219,7 @@
// Also disconnect from the peer.
if (mRemoteUnlockDevice != null) {
mCarTrustAgentBleManager.disconnectRemoteDevice();
+ mRemoteUnlockDevice = null;
}
}
@@ -138,6 +231,8 @@
synchronized (mDeviceLock) {
mRemoteUnlockDevice = null;
}
+ mPrevContext = null;
+ mCurrentContext = null;
}
void onRemoteDeviceConnected(BluetoothDevice device) {
@@ -149,6 +244,8 @@
queueMessageForLog("onRemoteDeviceConnected (addr:" + device.getAddress() + ")");
mRemoteUnlockDevice = device;
}
+ resetEncryptionState();
+ mCurrentUnlockState = UNLOCK_STATE_WAITING_FOR_UNIQUE_ID;
}
void onRemoteDeviceDisconnected(BluetoothDevice device) {
@@ -160,38 +257,283 @@
synchronized (mDeviceLock) {
mRemoteUnlockDevice = null;
}
+ resetEncryptionState();
+ mCurrentUnlockState = UNLOCK_STATE_WAITING_FOR_UNIQUE_ID;
+ }
+
+ void onUnlockDataReceived(byte[] value) {
+ switch (mCurrentUnlockState) {
+ case UNLOCK_STATE_WAITING_FOR_UNIQUE_ID:
+ mClientDeviceId = convertToDeviceId(value);
+ if (mClientDeviceId == null) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Phone not enrolled as a trusted device");
+ }
+ resetUnlockStateOnFailure();
+ return;
+ }
+ sendAckToClient(/* isEncrypted = */ false);
+ // Next step is to wait for the client to start the encryption handshake.
+ mCurrentUnlockState = UNLOCK_STATE_KEY_EXCHANGE_IN_PROGRESS;
+ break;
+ case UNLOCK_STATE_KEY_EXCHANGE_IN_PROGRESS:
+ try {
+ processKeyExchangeHandshakeMessage(value);
+ } catch (HandshakeException e) {
+ Log.e(TAG, "Handshake failure", e);
+ resetUnlockStateOnFailure();
+ }
+ break;
+ case UNLOCK_STATE_WAITING_FOR_CLIENT_AUTH:
+ if (!authenticateClient(value)) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG,
+ "HMAC from the phone is not correct. Cannot resume session. Need"
+ + " to re-enroll");
+ }
+ mTrustedDeviceService.clearEncryptionKey(mClientDeviceId);
+ resetUnlockStateOnFailure();
+
+ return;
+ }
+ sendServerAuthToClient();
+ mCurrentUnlockState = UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED;
+ break;
+ case UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED:
+ if (mEncryptionKey == null) {
+ Log.e(TAG, "Current session key null. Unexpected at this stage: "
+ + mCurrentUnlockState);
+ // Clear the previous session key. Need to re-enroll the trusted device.
+ mTrustedDeviceService.clearEncryptionKey(mClientDeviceId);
+ resetUnlockStateOnFailure();
+ }
+ // Save the current session to be used for authenticating the next session
+ mTrustedDeviceService.saveEncryptionKey(mClientDeviceId, mEncryptionKey.asBytes());
+
+ onUnlockTokenReceived(value);
+ mCurrentUnlockState = UNLOCK_STATE_TOKEN_RECEIVED;
+ // Let the phone know that the token was received.
+ sendAckToClient(/* isEncrypted = */ true);
+ break;
+ // TODO(b/131124919) Combine token and handle in the same packet
+ case UNLOCK_STATE_TOKEN_RECEIVED:
+ onUnlockHandleReceived(value);
+ mCurrentUnlockState = UNLOCK_STATE_HANDLE_RECEIVED;
+ break;
+ case UNLOCK_STATE_HANDLE_RECEIVED:
+ // Should never get here because the unlock process should be completed now.
+ Log.e(TAG, "Landed on unexpected state: " + mCurrentUnlockState);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void sendAckToClient(boolean isEncrypted) {
+ // Let the phone know that the handle was received.
+ byte[] ack = isEncrypted ? mEncryptionKey.encryptData(ACKNOWLEDGEMENT_MESSAGE)
+ : ACKNOWLEDGEMENT_MESSAGE;
+ mCarTrustAgentBleManager.sendUnlockMessage(mRemoteUnlockDevice, ack,
+ OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */ isEncrypted);
+ }
+
+ @Nullable
+ private String convertToDeviceId(byte[] id) {
+ // Validate if the id exists i.e., if the phone is enrolled already
+ UUID deviceId = Utils.bytesToUUID(id);
+ if (deviceId == null
+ || mTrustedDeviceService.getEncryptionKey(deviceId.toString()) == null) {
+ if (deviceId != null) {
+ Log.e(TAG, "Unknown phone connected: " + deviceId.toString());
+ }
+ return null;
+ }
+
+ return deviceId.toString();
+ }
+
+ private void processKeyExchangeHandshakeMessage(byte[] message) throws HandshakeException {
+ switch (mEncryptionState) {
+ case HandshakeMessage.HandshakeState.UNKNOWN:
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Responding to handshake init request.");
+ }
+
+ mHandshakeMessage = mEncryptionRunner.respondToInitRequest(message);
+ mEncryptionState = mHandshakeMessage.getHandshakeState();
+ mCarTrustAgentBleManager.sendUnlockMessage(mRemoteUnlockDevice,
+ mHandshakeMessage.getNextMessage(),
+ OperationType.ENCRYPTION_HANDSHAKE,
+ /* isPayloadEncrypted= */ false);
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Updated encryption state: " + mEncryptionState);
+ }
+ break;
+
+ case HandshakeMessage.HandshakeState.IN_PROGRESS:
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Continuing handshake.");
+ }
+
+ mHandshakeMessage = mEncryptionRunner.continueHandshake(message);
+ mEncryptionState = mHandshakeMessage.getHandshakeState();
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Updated encryption state: " + mEncryptionState);
+ }
+
+ // The state is updated after a call to continueHandshake(). Thus, need to check
+ // if we're in the next stage.
+ if (mEncryptionState == HandshakeMessage.HandshakeState.VERIFICATION_NEEDED) {
+ showVerificationCode();
+ return;
+ }
+
+ // control shouldn't get here with Ukey2
+ mCarTrustAgentBleManager.sendUnlockMessage(mRemoteUnlockDevice,
+ mHandshakeMessage.getNextMessage(),
+ OperationType.ENCRYPTION_HANDSHAKE, /*isPayloadEncrypted= */false);
+ break;
+ case HandshakeMessage.HandshakeState.VERIFICATION_NEEDED:
+ case HandshakeMessage.HandshakeState.FINISHED:
+ // Should never reach this case since this state should occur after a verification
+ // code has been accepted. But it should mean handshake is done and the message
+ // is one for the escrow token. Start Mutual Auth from server - compute MACs and
+ // send it over
+ showVerificationCode();
+ break;
+
+ default:
+ Log.w(TAG, "Encountered invalid handshake state: " + mEncryptionState);
+ break;
+ }
+ }
+
+ /**
+ * Verify the handshake.
+ * TODO(b/134073741) combine this with the method in CarTrustAgentEnrollmentService and
+ * have this take a boolean to blindly confirm the numeric code.
+ */
+ private void showVerificationCode() {
+ HandshakeMessage handshakeMessage;
+
+ // Blindly accept the verification code.
+ try {
+ handshakeMessage = mEncryptionRunner.verifyPin();
+ } catch (HandshakeException e) {
+ Log.e(TAG, "Verify pin failed for new keys - Unexpected");
+ resetUnlockStateOnFailure();
+ return;
+ }
+
+ if (handshakeMessage.getHandshakeState() != HandshakeMessage.HandshakeState.FINISHED) {
+ Log.e(TAG, "Handshake not finished after calling verify PIN. Instead got state: "
+ + handshakeMessage.getHandshakeState());
+ resetUnlockStateOnFailure();
+ return;
+ }
+
+ mEncryptionState = HandshakeMessage.HandshakeState.FINISHED;
+ mEncryptionKey = handshakeMessage.getKey();
+ mCurrentContext = D2DConnectionContext.fromSavedSession(mEncryptionKey.asBytes());
+
+ if (mClientDeviceId == null) {
+ resetUnlockStateOnFailure();
+ return;
+ }
+ byte[] oldSessionKeyBytes = mTrustedDeviceService.getEncryptionKey(mClientDeviceId);
+ if (oldSessionKeyBytes == null) {
+ Log.e(TAG,
+ "Could not retrieve previous session keys! Have to re-enroll trusted device");
+ resetUnlockStateOnFailure();
+ return;
+ }
+
+ mPrevContext = D2DConnectionContext.fromSavedSession(oldSessionKeyBytes);
+ if (mPrevContext == null) {
+ resetUnlockStateOnFailure();
+ return;
+ }
+
+ // Now wait for the phone to send its MAC.
+ mCurrentUnlockState = UNLOCK_STATE_WAITING_FOR_CLIENT_AUTH;
+ }
+
+ private void sendServerAuthToClient() {
+ byte[] resumeBytes = computeMAC(mPrevContext, mCurrentContext, SERVER);
+ if (resumeBytes == null) {
+ return;
+ }
+ // send to client
+ mCarTrustAgentBleManager.sendUnlockMessage(mRemoteUnlockDevice, resumeBytes,
+ OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */false);
+ }
+
+ @Nullable
+ private byte[] computeMAC(D2DConnectionContext previous, D2DConnectionContext next,
+ byte[] info) {
+ try {
+ SecretKeySpec inputKeyMaterial = new SecretKeySpec(
+ Utils.concatByteArrays(previous.getSessionUnique(), next.getSessionUnique()),
+ "" /* key type is just plain raw bytes */);
+ return CryptoOps.hkdf(inputKeyMaterial, RESUME, info);
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ // Does not happen in practice
+ Log.e(TAG, "Compute MAC failed");
+ return null;
+ }
+ }
+
+ private boolean authenticateClient(byte[] message) {
+ if (message.length != RESUME_HMAC_LENGTH) {
+ Log.e(TAG, "failing because message.length is " + message.length);
+ return false;
+ }
+ return MessageDigest.isEqual(message,
+ computeMAC(mPrevContext, mCurrentContext, CLIENT));
}
void onUnlockTokenReceived(byte[] value) {
synchronized (mTokenLock) {
mUnlockToken = value;
}
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Unlock Token: " + Utils.byteArrayToHexString(mUnlockToken));
- }
- queueMessageForLog("onUnlockTokenReceived");
- if (mUnlockToken == null || mUnlockHandle == null) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Unlock Handle not available yet");
- }
- return;
- }
- if (mUnlockDelegate == null) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "No Unlock delegate");
- }
- return;
- }
- mUnlockDelegate.onUnlockDataReceived(
- mTrustedDeviceService.getUserHandleByTokenHandle(Utils.bytesToLong(mUnlockHandle)),
- mUnlockToken,
- Utils.bytesToLong(mUnlockHandle));
- synchronized (mTokenLock) {
- mUnlockToken = null;
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Unlock Token received: " + Utils.byteArrayToHexString(mUnlockToken));
}
- synchronized (mHandleLock) {
- mUnlockHandle = null;
+
+ queueMessageForLog("onUnlockTokenReceived");
+ }
+
+ /**
+ * Reset the whole unlock state. Disconnects from the peer device
+ *
+ * <p>This method should be called from any stage in the middle of unlock where we
+ * encounter a failure.
+ */
+ private void resetUnlockStateOnFailure() {
+ mCarTrustAgentBleManager.disconnectRemoteDevice();
+ resetEncryptionState();
+ }
+
+ /**
+ * Resets the encryption status of this service.
+ *
+ * <p>This method should be called each time a device connects so that a new handshake can be
+ * started and encryption keys exchanged.
+ */
+ private void resetEncryptionState() {
+ mEncryptionRunner = EncryptionRunnerFactory.newRunner();
+ mHandshakeMessage = null;
+ mEncryptionKey = null;
+ mEncryptionState = HandshakeMessage.HandshakeState.UNKNOWN;
+ mCurrentUnlockState = UNLOCK_STATE_WAITING_FOR_UNIQUE_ID;
+ if (mCurrentContext != null) {
+ mCurrentContext = null;
+ }
+ if (mPrevContext != null) {
+ mPrevContext = null;
}
}
@@ -199,10 +541,13 @@
synchronized (mHandleLock) {
mUnlockHandle = value;
}
+
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Unlock Handle: " + Utils.byteArrayToHexString(mUnlockHandle));
+ Log.d(TAG, "Unlock Handl received: " + Utils.byteArrayToHexString(mUnlockHandle));
}
+
queueMessageForLog("onUnlockHandleReceived");
+
if (mUnlockToken == null || mUnlockHandle == null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Unlock Token not available yet");
@@ -216,6 +561,7 @@
}
return;
}
+
mUnlockDelegate.onUnlockDataReceived(
mTrustedDeviceService.getUserHandleByTokenHandle(Utils.bytesToLong(mUnlockHandle)),
mUnlockToken,
@@ -227,6 +573,7 @@
synchronized (mHandleLock) {
mUnlockHandle = null;
}
+ resetEncryptionState();
}
void dump(PrintWriter writer) {
diff --git a/service/src/com/android/car/trust/CarTrustedDeviceService.java b/service/src/com/android/car/trust/CarTrustedDeviceService.java
index 2948bec..cc79eff 100644
--- a/service/src/com/android/car/trust/CarTrustedDeviceService.java
+++ b/service/src/com/android/car/trust/CarTrustedDeviceService.java
@@ -16,6 +16,7 @@
package com.android.car.trust;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.bluetooth.BluetoothDevice;
import android.car.trust.TrustedDeviceInfo;
@@ -26,8 +27,6 @@
import android.util.Base64;
import android.util.Log;
-import androidx.annotation.Nullable;
-
import com.android.car.CarServiceBase;
import com.android.car.R;
import com.android.car.Utils;
@@ -51,6 +50,7 @@
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.GCMParameterSpec;
/**
* The part of the Car service that enables the Trusted device feature. Trusted Device is a feature
@@ -63,12 +63,21 @@
*/
public class CarTrustedDeviceService implements CarServiceBase {
private static final String TAG = CarTrustedDeviceService.class.getSimpleName();
+
private static final String UNIQUE_ID_KEY = "CTABM_unique_id";
private static final String PREF_ENCRYPTION_KEY_PREFIX = "CTABM_encryption_key";
private static final String KEY_ALIAS = "Ukey2Key";
private static final String CIPHER_TRANSFORMATION = "AES/GCM/NoPadding";
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
+ private static final String IV_SPEC_SEPARATOR = ";";
+
+ // The length of the authentication tag for a cipher in GCM mode. The GCM specification states
+ // that this length can only have the values {128, 120, 112, 104, 96}. Using the highest
+ // possible value.
+ private static final int GCM_AUTHENTICATION_TAG_LENGTH = 128;
+
private static final int RANDOM_NAME_LENGTH = 6;
+
private final Context mContext;
private CarTrustAgentEnrollmentService mCarTrustAgentEnrollmentService;
private CarTrustAgentUnlockService mCarTrustAgentUnlockService;
@@ -202,8 +211,9 @@
}
} else {
mUniqueId = UUID.randomUUID();
- prefs.edit().putString(UNIQUE_ID_KEY, mUniqueId.toString()).commit();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
+ if (!prefs.edit().putString(UNIQUE_ID_KEY, mUniqueId.toString()).commit()) {
+ mUniqueId = null;
+ } else if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Generated new trusted unique id: "
+ prefs.getString(UNIQUE_ID_KEY, ""));
}
@@ -221,13 +231,21 @@
@Nullable
byte[] getEncryptionKey(String deviceId) {
SharedPreferences prefs = getSharedPrefs();
- if (!prefs.contains(deviceId)) {
+ String key = PREF_ENCRYPTION_KEY_PREFIX + deviceId;
+ if (!prefs.contains(key)) {
return null;
}
- byte[] encryptedKey = Base64.decode(
- prefs.getString(PREF_ENCRYPTION_KEY_PREFIX + deviceId, null),
- Base64.DEFAULT);
- return decryptWithKeyStore(KEY_ALIAS, encryptedKey);
+
+ // This value will not be "null" because we already checked via a call to contains().
+ String[] values = prefs.getString(key, null).split(IV_SPEC_SEPARATOR);
+
+ if (values.length != 2) {
+ return null;
+ }
+
+ byte[] encryptedKey = Base64.decode(values[0], Base64.DEFAULT);
+ byte[] ivSpec = Base64.decode(values[1], Base64.DEFAULT);
+ return decryptWithKeyStore(KEY_ALIAS, encryptedKey, ivSpec);
}
/**
@@ -235,14 +253,36 @@
*
* @param deviceId did of trusted device
* @param encryptionKey encryption key
+ * @return {@code true} if the operation succeeded
*/
- void saveEncryptionKey(String deviceId, byte[] encryptionKey) {
- byte[] encryptedKey = encryptWithKeyStore(KEY_ALIAS, encryptionKey);
- getSharedPrefs()
+ boolean saveEncryptionKey(@Nullable String deviceId, @Nullable byte[] encryptionKey) {
+ if (encryptionKey == null || deviceId == null) {
+ return false;
+ }
+ String encryptedKey = encryptWithKeyStore(KEY_ALIAS, encryptionKey);
+ if (encryptedKey == null) {
+ return false;
+ }
+ if (getSharedPrefs().contains(deviceId)) {
+ clearEncryptionKey(deviceId);
+ }
+
+ return getSharedPrefs()
.edit()
- .putString(PREF_ENCRYPTION_KEY_PREFIX + deviceId,
- Base64.encodeToString(encryptedKey, Base64.DEFAULT))
- .apply();
+ .putString(PREF_ENCRYPTION_KEY_PREFIX + deviceId, encryptedKey)
+ .commit();
+ }
+
+ /**
+ * Clear the encryption key for the given device
+ *
+ * @param deviceId id of the peer device
+ */
+ void clearEncryptionKey(@Nullable String deviceId) {
+ if (deviceId == null) {
+ return;
+ }
+ getSharedPrefs().edit().remove(deviceId);
}
/**
@@ -262,12 +302,18 @@
/**
* Encrypt value with designated key
*
+ * <p>The encrypted value is of the form:
+ *
+ * <p>key + IV_SPEC_SEPARATOR + ivSpec
+ *
+ * <p>The {@code ivSpec} is needed to decrypt this key later on.
+ *
* @param keyAlias KeyStore alias for key to use
* @param value a value to encrypt
* @return encrypted value, null if unable to encrypt
*/
@Nullable
- byte[] encryptWithKeyStore(String keyAlias, byte[] value) {
+ String encryptWithKeyStore(String keyAlias, byte[] value) {
if (value == null) {
return null;
}
@@ -276,7 +322,10 @@
try {
Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, key);
- return cipher.doFinal(value);
+ return new StringBuffer(Base64.encodeToString(cipher.doFinal(value), Base64.DEFAULT))
+ .append(IV_SPEC_SEPARATOR)
+ .append(Base64.encodeToString(cipher.getIV(), Base64.DEFAULT))
+ .toString();
} catch (IllegalBlockSizeException
| BadPaddingException
| NoSuchAlgorithmException
@@ -296,7 +345,7 @@
* @return decrypted value, null if unable to decrypt
*/
@Nullable
- byte[] decryptWithKeyStore(String keyAlias, byte[] value) {
+ byte[] decryptWithKeyStore(String keyAlias, byte[] value, byte[] ivSpec) {
if (value == null) {
return null;
}
@@ -304,14 +353,16 @@
try {
Key key = getKeyStoreKey(keyAlias);
Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
- cipher.init(Cipher.DECRYPT_MODE, key);
+ cipher.init(Cipher.DECRYPT_MODE, key,
+ new GCMParameterSpec(GCM_AUTHENTICATION_TAG_LENGTH, ivSpec));
return cipher.doFinal(value);
} catch (IllegalBlockSizeException
| BadPaddingException
| NoSuchAlgorithmException
| NoSuchPaddingException
| IllegalStateException
- | InvalidKeyException e) {
+ | InvalidKeyException
+ | InvalidAlgorithmParameterException e) {
Log.e(TAG, "Unable to decrypt value with key " + keyAlias, e);
return null;
}
diff --git a/service/src/com/android/car/vms/VmsBrokerService.java b/service/src/com/android/car/vms/VmsBrokerService.java
index 216c8fd..26626ff 100644
--- a/service/src/com/android/car/vms/VmsBrokerService.java
+++ b/service/src/com/android/car/vms/VmsBrokerService.java
@@ -22,19 +22,24 @@
import android.car.vms.VmsLayersOffering;
import android.car.vms.VmsOperationRecorder;
import android.car.vms.VmsSubscriptionState;
+import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.IBinder;
+import android.os.Process;
import android.util.Log;
import com.android.car.VmsLayersAvailability;
import com.android.car.VmsPublishersInfo;
import com.android.car.VmsRouting;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.IntSupplier;
/**
* Broker service facilitating subscription handling and message passing between
@@ -44,15 +49,26 @@
private static final boolean DBG = true;
private static final String TAG = "VmsBrokerService";
+ @VisibleForTesting
+ static final String HAL_CLIENT = "HalClient";
+
+ @VisibleForTesting
+ static final String UNKNOWN_PACKAGE = "UnknownPackage";
+
private CopyOnWriteArrayList<PublisherListener> mPublisherListeners =
new CopyOnWriteArrayList<>();
private CopyOnWriteArrayList<SubscriberListener> mSubscriberListeners =
new CopyOnWriteArrayList<>();
+ private PackageManager mPackageManager;
+ private IntSupplier mGetCallingPid;
+ private IntSupplier mGetCallingUid;
private final Object mLock = new Object();
@GuardedBy("mLock")
private final VmsRouting mRouting = new VmsRouting();
@GuardedBy("mLock")
+ private final Map<IBinder, String> mBinderPackage = new HashMap<>();
+ @GuardedBy("mLock")
private final Map<IBinder, Map<Integer, VmsLayersOffering>> mOfferings = new HashMap<>();
@GuardedBy("mLock")
private final VmsLayersAvailability mAvailableLayers = new VmsLayersAvailability();
@@ -95,8 +111,17 @@
/**
* Constructs new broker service.
*/
- public VmsBrokerService() {
+ public VmsBrokerService(PackageManager packageManager) {
+ this(packageManager, Binder::getCallingPid, Binder::getCallingUid);
+ }
+
+ @VisibleForTesting
+ VmsBrokerService(PackageManager packageManager, IntSupplier getCallingPid,
+ IntSupplier getCallingUid) {
if (DBG) Log.d(TAG, "Started VmsBrokerService!");
+ mPackageManager = packageManager;
+ mGetCallingPid = getCallingPid;
+ mGetCallingUid = getCallingUid;
}
/**
@@ -143,6 +168,8 @@
public void addSubscription(IVmsSubscriberClient subscriber) {
synchronized (mLock) {
mRouting.addSubscription(subscriber);
+ // Add mapping from binder to package name of subscriber.
+ mBinderPackage.computeIfAbsent(subscriber.asBinder(), k -> getCallingPackage());
}
}
@@ -172,6 +199,9 @@
// Add the listeners subscription to the layer
mRouting.addSubscription(subscriber, layer);
+
+ // Add mapping from binder to package name of subscriber.
+ mBinderPackage.computeIfAbsent(subscriber.asBinder(), k -> getCallingPackage());
}
if (firstSubscriptionForLayer) {
notifyOfSubscriptionChange();
@@ -219,6 +249,9 @@
// Add the listeners subscription to the layer
mRouting.addSubscription(subscriber, layer, publisherId);
+
+ // Add mapping from binder to package name of subscriber.
+ mBinderPackage.computeIfAbsent(subscriber.asBinder(), k -> getCallingPackage());
}
if (firstSubscriptionForLayer) {
notifyOfSubscriptionChange();
@@ -263,6 +296,9 @@
boolean subscriptionStateChanged;
synchronized (mLock) {
subscriptionStateChanged = mRouting.removeDeadSubscriber(subscriber);
+
+ // Remove mapping from binder to package name of subscriber.
+ mBinderPackage.remove(subscriber.asBinder());
}
if (subscriptionStateChanged) {
notifyOfSubscriptionChange();
@@ -358,6 +394,15 @@
}
}
+ /**
+ * Gets the package name for a given IVmsSubscriberClient
+ */
+ public String getPackageName(IVmsSubscriberClient subscriber) {
+ synchronized (mLock) {
+ return mBinderPackage.get(subscriber.asBinder());
+ }
+ }
+
private void updateLayerAvailability() {
Set<VmsLayersOffering> allPublisherOfferings = new HashSet<>();
synchronized (mLock) {
@@ -388,4 +433,21 @@
listener.onLayersAvailabilityChange(availableLayers);
}
}
+
+ // If we're in a binder call, returns back the package name of the caller of the binder call.
+ private String getCallingPackage() {
+ int callingPid = mGetCallingPid.getAsInt();
+ // Since the HAL lives in the same process, if the callingPid is equal to this process's
+ // PID, we know it's the HAL client.
+ if (callingPid == Process.myPid()) {
+ return HAL_CLIENT;
+ }
+ int callingUid = mGetCallingUid.getAsInt();
+ String packageName = mPackageManager.getNameForUid(callingUid);
+ if (packageName == null) {
+ return UNKNOWN_PACKAGE;
+ } else {
+ return packageName;
+ }
+ }
}
diff --git a/service/src/com/android/car/vms/VmsClientManager.java b/service/src/com/android/car/vms/VmsClientManager.java
index 5f5969e..d3c39ff 100644
--- a/service/src/com/android/car/vms/VmsClientManager.java
+++ b/service/src/com/android/car/vms/VmsClientManager.java
@@ -40,6 +40,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Manages service connections lifecycle for VMS publisher clients.
@@ -76,7 +77,6 @@
private final Handler mHandler;
private final CarUserService mUserService;
private final CarUserManagerHelper mUserManagerHelper;
- private final IBinder mHalClient;
private final int mMillisBeforeRebind;
@GuardedBy("mListeners")
@@ -84,6 +84,8 @@
@GuardedBy("mSystemClients")
private final Map<String, ClientConnection> mSystemClients = new ArrayMap<>();
@GuardedBy("mSystemClients")
+ private IBinder mHalClient;
+ @GuardedBy("mSystemClients")
private boolean mSystemUserUnlocked;
@GuardedBy("mCurrentUserClients")
@@ -91,6 +93,9 @@
@GuardedBy("mCurrentUserClients")
private int mCurrentUser;
+ @GuardedBy("mRebindCounts")
+ private final Map<String, AtomicLong> mRebindCounts = new ArrayMap<>();
+
@VisibleForTesting
final Runnable mSystemUserUnlockedListener = () -> {
synchronized (mSystemClients) {
@@ -132,9 +137,9 @@
mHandler = new Handler(Looper.getMainLooper());
mUserService = userService;
mUserManagerHelper = userManagerHelper;
- mHalClient = halService.getPublisherClient();
mMillisBeforeRebind = mContext.getResources().getInteger(
com.android.car.R.integer.millisecondsBeforeRebindToVmsPublisher);
+ halService.setPublisherConnectionCallbacks(this::onHalConnected, this::onHalDisconnected);
}
@Override
@@ -163,10 +168,30 @@
@Override
public void dump(PrintWriter writer) {
writer.println("*" + getClass().getSimpleName() + "*");
- writer.println("mListeners:" + mListeners);
- writer.println("mSystemClients:" + mSystemClients.keySet());
- writer.println("mCurrentUser:" + mCurrentUser);
- writer.println("mCurrentUserClients:" + mCurrentUserClients.keySet());
+ synchronized (mSystemClients) {
+ writer.println("mHalClient: " + (mHalClient != null ? "connected" : "disconnected"));
+ writer.println("mSystemClients:");
+ dumpConnections(writer, mSystemClients);
+ }
+ synchronized (mCurrentUserClients) {
+ writer.println("mCurrentUserClients:");
+ dumpConnections(writer, mCurrentUserClients);
+ writer.println("mCurrentUser:" + mCurrentUser);
+ }
+ synchronized (mRebindCounts) {
+ writer.println("mRebindCounts:");
+ for (Map.Entry<String, AtomicLong> entry : mRebindCounts.entrySet()) {
+ writer.printf("\t%s: %s\n", entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ private void dumpConnections(PrintWriter writer, Map<String, ClientConnection> connectionMap) {
+ for (ClientConnection connection : connectionMap.values()) {
+ writer.printf("\t%s: %s\n",
+ connection.mName.getPackageName(),
+ connection.mIsBound ? "connected" : "disconnected");
+ }
}
/**
@@ -273,8 +298,10 @@
}
private void notifyListenerOfConnectedClients(ConnectionListener listener) {
- listener.onClientConnected(HAL_CLIENT_NAME, mHalClient);
synchronized (mSystemClients) {
+ if (mHalClient != null) {
+ listener.onClientConnected(HAL_CLIENT_NAME, mHalClient);
+ }
mSystemClients.values().forEach(conn -> conn.notifyIfConnected(listener));
}
synchronized (mCurrentUserClients) {
@@ -298,6 +325,23 @@
}
}
+ private void onHalConnected(IBinder halClient) {
+ synchronized (mSystemClients) {
+ mHalClient = halClient;
+ notifyListenersOnClientConnected(HAL_CLIENT_NAME, mHalClient);
+ }
+ }
+
+ private void onHalDisconnected() {
+ synchronized (mSystemClients) {
+ mHalClient = null;
+ notifyListenersOnClientDisconnected(HAL_CLIENT_NAME);
+ }
+ synchronized (mRebindCounts) {
+ mRebindCounts.computeIfAbsent(HAL_CLIENT_NAME, k -> new AtomicLong()).incrementAndGet();
+ }
+ }
+
class ClientConnection implements ServiceConnection {
private final ComponentName mName;
private final UserHandle mUser;
@@ -359,6 +403,10 @@
}
if (!mIsTerminated) {
mHandler.postDelayed(this::bind, mMillisBeforeRebind);
+ synchronized (mRebindCounts) {
+ mRebindCounts.computeIfAbsent(mName.getPackageName(), k -> new AtomicLong())
+ .incrementAndGet();
+ }
}
}
diff --git a/tests/BugReportApp/Android.mk b/tests/BugReportApp/Android.mk
new file mode 100644
index 0000000..f948b82
--- /dev/null
+++ b/tests/BugReportApp/Android.mk
@@ -0,0 +1,78 @@
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := BugReportApp
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_AAPT_FLAGS := --auto-add-overlay
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_CERTIFICATE := platform
+
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_JAVA_LIBRARIES += \
+ android.car
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ androidx.recyclerview_recyclerview \
+ br_google-api-java-client \
+ br_google-api-client-android \
+ br_google-oauth-client \
+ br_google-http-client \
+ br_google-http-client-android \
+ br_google-http-client-jackson2 \
+ br_jackson-core \
+ br_gson-2.1 \
+ br_google-storage-services \
+ br_apache_commons \
+ guava \
+ jsr305
+
+LOCAL_REQUIRED_MODULES := privapp_whitelist_com.google.android.car.bugreport
+
+include $(BUILD_PACKAGE)
+
+# ==== prebuilt library ========================
+include $(CLEAR_VARS)
+
+COMMON_LIBS_PATH := ../../../../../prebuilts/tools/common/m2/repository
+
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+ br_google-api-java-client:libs/google-api-client-1.25.0.jar \
+ br_google-api-client-android:libs/google-api-client-android-1.25.0.jar \
+ br_google-oauth-client:libs/google-oauth-client-1.25.0.jar \
+ br_google-http-client:libs/google-http-client-1.25.0.jar \
+ br_google-http-client-android:libs/google-http-client-android-1.25.0.jar \
+ br_jackson-core:libs/jackson-core-2.9.6.jar \
+ br_gson-2.1:libs/gson-2.1.jar \
+ br_google-http-client-jackson2:libs/google-http-client-jackson2-1.25.0.jar \
+ br_google-storage-services:libs/google-api-services-storage-v1-rev136-1.25.0.jar \
+ br_apache_commons:$(COMMON_LIBS_PATH)/org/eclipse/tycho/tycho-bundles-external/0.18.1/eclipse/plugins/org.apache.commons.codec_1.4.0.v201209201156.jar
+
+include $(BUILD_MULTI_PREBUILT)
diff --git a/tests/BugReportApp/AndroidManifest.xml b/tests/BugReportApp/AndroidManifest.xml
new file mode 100644
index 0000000..ac27207
--- /dev/null
+++ b/tests/BugReportApp/AndroidManifest.xml
@@ -0,0 +1,71 @@
+<?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"
+ package="com.google.android.car.bugreport"
+ android:versionCode="6"
+ android:versionName="1.5.0">
+
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+ <uses-permission android:name="android.permission.DUMP"/>
+
+ <application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
+ <activity android:name=".BugReportInfoActivity"
+ android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.VIEW"/>
+ </intent-filter>
+ </activity>
+
+ <!-- singleInstance allows starting bugreport dialog when BugReportInfoActivity is open. -->
+ <activity android:name=".BugReportActivity"
+ android:theme="@android:style/Theme.DeviceDefault.Dialog"
+ android:exported="true"
+ android:launchMode="singleInstance">
+ </activity>
+
+ <service android:name=".BugReportService"
+ android:exported="false"/>
+
+ <service android:name="com.google.android.car.bugreport.UploadJob"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="true"/>
+
+ <receiver android:name=".StartUpBootReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED"/>
+ </intent-filter>
+ </receiver>
+
+ <provider android:name="com.google.android.car.bugreport.BugStorageProvider"
+ android:authorities="com.google.android.car.bugreport"
+ android:exported="false"
+ android:singleUser="true"
+ android:multiprocess="false">
+ </provider>
+ </application>
+</manifest>
diff --git a/tests/BugReportApp/README.md b/tests/BugReportApp/README.md
new file mode 100644
index 0000000..1205ac4
--- /dev/null
+++ b/tests/BugReportApp/README.md
@@ -0,0 +1,17 @@
+# AAE BugReport App
+
+## Flow
+
+1. User long presses Notification icon
+2. It opens BugReportActivity as dialog under current user (e.g. u10)
+3. BugReportActivity connects to BugReportService and checks if a bugreporting is running.
+4. If bugreporting is already running it shows in progress dialog
+5. Otherwise it creates MetaBugReport record in a local db and starts recording audio message.
+6. When the submit button is clicked, it saves the audio message in temp directory and starts
+ BugReportService.
+7. If the drivers cancels the dialog, the BugReportActivity deletes temp directory and closes the
+ activity.
+8. BugReportService running under current user (e.g. u10) starts collecting logs using dumpstate,
+ and when finished it updates MetaBugReport using BugStorageProvider.
+9. BugStorageProvider is running under u0, it schedules UploadJob.
+10. UploadJob runs SimpleUploaderAsyncTask to upload the bugreport.
diff --git a/tests/BugReportApp/libs/google-api-client-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-1.25.0.jar
new file mode 100644
index 0000000..f1e65b2
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-client-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-android-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-android-1.25.0.jar
new file mode 100644
index 0000000..2e62e7a
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-client-android-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-gson-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-gson-1.25.0.jar
new file mode 100644
index 0000000..734491d
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-client-gson-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-jackson2-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-jackson2-1.25.0.jar
new file mode 100644
index 0000000..da08ebe
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-client-jackson2-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-services-storage-v1-rev136-1.25.0.jar b/tests/BugReportApp/libs/google-api-services-storage-v1-rev136-1.25.0.jar
new file mode 100644
index 0000000..2f265eb
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-services-storage-v1-rev136-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-1.25.0.jar
new file mode 100644
index 0000000..84c8ce3
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-android-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-android-1.25.0.jar
new file mode 100644
index 0000000..f2bb0d4
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-android-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-gson-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-gson-1.25.0.jar
new file mode 100644
index 0000000..158c0c8
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-gson-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-jackson2-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-jackson2-1.25.0.jar
new file mode 100644
index 0000000..34f5646
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-jackson2-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-jdo-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-jdo-1.25.0.jar
new file mode 100644
index 0000000..dcb7461
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-jdo-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-oauth-client-1.25.0.jar b/tests/BugReportApp/libs/google-oauth-client-1.25.0.jar
new file mode 100644
index 0000000..1304c30
--- /dev/null
+++ b/tests/BugReportApp/libs/google-oauth-client-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/gson-2.1.jar b/tests/BugReportApp/libs/gson-2.1.jar
new file mode 100644
index 0000000..83c5c99
--- /dev/null
+++ b/tests/BugReportApp/libs/gson-2.1.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/httpclient-4.5.5.jar b/tests/BugReportApp/libs/httpclient-4.5.5.jar
new file mode 100644
index 0000000..7796b0e
--- /dev/null
+++ b/tests/BugReportApp/libs/httpclient-4.5.5.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/jackson-core-2.9.6.jar b/tests/BugReportApp/libs/jackson-core-2.9.6.jar
new file mode 100644
index 0000000..09e7dd2
--- /dev/null
+++ b/tests/BugReportApp/libs/jackson-core-2.9.6.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/jdo2-api-2.3-eb.jar b/tests/BugReportApp/libs/jdo2-api-2.3-eb.jar
new file mode 100644
index 0000000..a039ae7
--- /dev/null
+++ b/tests/BugReportApp/libs/jdo2-api-2.3-eb.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/readme.txt b/tests/BugReportApp/libs/readme.txt
new file mode 100644
index 0000000..430efde
--- /dev/null
+++ b/tests/BugReportApp/libs/readme.txt
@@ -0,0 +1 @@
+Downloaded from https://developers.google.com/api-client-library/java/google-api-java-client/download
diff --git a/car-cluster-logging-renderer/res/drawable-hdpi/ic_launcher.png b/tests/BugReportApp/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from car-cluster-logging-renderer/res/drawable-hdpi/ic_launcher.png
rename to tests/BugReportApp/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-hdpi/ic_upload.png b/tests/BugReportApp/res/drawable-hdpi/ic_upload.png
new file mode 100644
index 0000000..2f283fd
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-hdpi/ic_upload.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim0.png b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim0.png
new file mode 100644
index 0000000..910de29
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim1.png b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim1.png
new file mode 100644
index 0000000..0b1aa34
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim2.png b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim2.png
new file mode 100644
index 0000000..bc1877d
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim3.png b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim3.png
new file mode 100644
index 0000000..9f41092
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim4.png b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim4.png
new file mode 100644
index 0000000..5fa6305
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim5.png b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim5.png
new file mode 100644
index 0000000..703759a
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-hdpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/car-cluster-logging-renderer/res/drawable-ldpi/ic_launcher.png b/tests/BugReportApp/res/drawable-ldpi/ic_launcher.png
similarity index 100%
rename from car-cluster-logging-renderer/res/drawable-ldpi/ic_launcher.png
rename to tests/BugReportApp/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-ldpi/ic_upload.png b/tests/BugReportApp/res/drawable-ldpi/ic_upload.png
new file mode 100644
index 0000000..2f283fd
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-ldpi/ic_upload.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim0.png b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim0.png
new file mode 100644
index 0000000..12c0e21
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim1.png b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim1.png
new file mode 100644
index 0000000..f5ec4ac
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim2.png b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim2.png
new file mode 100644
index 0000000..4900ebd
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim3.png b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim3.png
new file mode 100644
index 0000000..aff9ebd
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim4.png b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim4.png
new file mode 100644
index 0000000..2eb65db
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim5.png b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim5.png
new file mode 100644
index 0000000..a9f2448
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-ldpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/car-cluster-logging-renderer/res/drawable-mdpi/ic_launcher.png b/tests/BugReportApp/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from car-cluster-logging-renderer/res/drawable-mdpi/ic_launcher.png
rename to tests/BugReportApp/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-mdpi/ic_upload.png b/tests/BugReportApp/res/drawable-mdpi/ic_upload.png
new file mode 100644
index 0000000..2f283fd
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-mdpi/ic_upload.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim0.png b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim0.png
new file mode 100644
index 0000000..25324f6
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim1.png b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim1.png
new file mode 100644
index 0000000..6d1fb4a
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim2.png b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim2.png
new file mode 100644
index 0000000..4c3e963
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim3.png b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim3.png
new file mode 100644
index 0000000..2aae625
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim4.png b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim4.png
new file mode 100644
index 0000000..55dbe12
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim5.png b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim5.png
new file mode 100644
index 0000000..53fda44
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-mdpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/car-cluster-logging-renderer/res/drawable-xhdpi/ic_launcher.png b/tests/BugReportApp/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from car-cluster-logging-renderer/res/drawable-xhdpi/ic_launcher.png
rename to tests/BugReportApp/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-xhdpi/ic_upload.png b/tests/BugReportApp/res/drawable-xhdpi/ic_upload.png
new file mode 100644
index 0000000..2f283fd
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-xhdpi/ic_upload.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim0.png b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim0.png
new file mode 100644
index 0000000..73cbc96
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim1.png b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim1.png
new file mode 100644
index 0000000..3e39abb
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim2.png b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim2.png
new file mode 100644
index 0000000..fc9b0de
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim3.png b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim3.png
new file mode 100644
index 0000000..94bc012
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim4.png b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim4.png
new file mode 100644
index 0000000..e6b5857
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim5.png b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim5.png
new file mode 100644
index 0000000..f1df0c8
--- /dev/null
+++ b/tests/BugReportApp/res/drawable-xhdpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/tests/BugReportApp/res/drawable/download_animation.xml b/tests/BugReportApp/res/drawable/download_animation.xml
new file mode 100644
index 0000000..b2baf82
--- /dev/null
+++ b/tests/BugReportApp/res/drawable/download_animation.xml
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+<animation-list android:id="@+id/selected" android:oneshot="false"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/stat_sys_download_anim0" android:duration="50" />
+ <item android:drawable="@drawable/stat_sys_download_anim1" android:duration="50" />
+ <item android:drawable="@drawable/stat_sys_download_anim2" android:duration="50" />
+ <item android:drawable="@drawable/stat_sys_download_anim3" android:duration="50" />
+ <item android:drawable="@drawable/stat_sys_download_anim4" android:duration="50" />
+ <item android:drawable="@drawable/stat_sys_download_anim5" android:duration="50" />
+</animation-list>
diff --git a/tests/BugReportApp/res/layout/bug_info_view.xml b/tests/BugReportApp/res/layout/bug_info_view.xml
new file mode 100644
index 0000000..a02df20
--- /dev/null
+++ b/tests/BugReportApp/res/layout/bug_info_view.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="10dp">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TITLE"
+ android:textColor="@android:color/holo_green_light"
+ android:textSize="28sp" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="USER"
+ android:textColor="@android:color/holo_red_dark"
+ android:textSize="28sp" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="BUG TIME"
+ android:textColor="@android:color/holo_red_light"
+ android:textSize="28sp" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="STATUS"
+ android:textColor="@android:color/holo_orange_light"
+ android:textSize="28sp" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="OTHER"
+ android:textColor="@android:color/holo_blue_dark"
+ android:textSize="28sp" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="10dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/bug_info_row_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:textSize="28sp" />
+
+
+ <TextView
+ android:id="@+id/bug_info_row_user"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="28sp" />
+
+
+ <TextView
+ android:id="@+id/bug_info_row_timestamp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="28sp" />
+
+
+ <TextView
+ android:id="@+id/bug_info_row_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="28sp" />
+
+
+ <TextView
+ android:id="@+id/bug_info_row_message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="28sp" />
+
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/BugReportApp/res/layout/bug_report_activity.xml b/tests/BugReportApp/res/layout/bug_report_activity.xml
new file mode 100644
index 0000000..bd28000
--- /dev/null
+++ b/tests/BugReportApp/res/layout/bug_report_activity.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/submit_bug_report_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/bug_report_padding"
+ android:background="@color/bugreport_background"
+ android:visibility="gone"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/bug_report_title_size"
+ android:textColor="@color/bugreport_text"
+ android:gravity="center"
+ android:text="@string/bugreport_dialog_title"/>
+ <com.google.android.car.bugreport.VoiceRecordingView
+ android:id="@+id/voice_recording_view"
+ android:layout_marginTop="@dimen/bug_report_voice_recording_margin_top"
+ android:layout_height="@dimen/bug_report_voice_recording_height"
+ android:layout_width="match_parent"/>
+ <TextView
+ android:id="@+id/voice_recording_finished_text_view"
+ android:layout_marginTop="@dimen/bug_report_voice_recording_margin_top"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/bug_report_voice_recording_height"
+ android:textSize="@dimen/bug_report_text_size"
+ android:textColor="@color/bugreport_text"
+ android:gravity="center"
+ android:visibility="gone"
+ android:text="@string/bugreport_dialog_recording_finished"/>
+ <Button
+ android:id="@+id/button_submit"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/bug_report_button_margin_top"
+ android:padding="@dimen/bug_report_primary_button_padding"
+ android:background="@color/bugreport_button_background"
+ android:textColor="@color/bugreport_button_foreground"
+ android:textSize="@dimen/bug_report_button_text_size"
+ android:text="@string/bugreport_dialog_submit"/>
+ <Button
+ android:id="@+id/button_cancel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/bug_report_button_margin_top"
+ android:padding="@dimen/bug_report_secondary_button_padding"
+ android:background="@color/bugreport_button_background"
+ android:textColor="@color/bugreport_button_foreground"
+ android:textSize="@dimen/bug_report_button_text_size"
+ android:text="@string/bugreport_dialog_cancel"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/in_progress_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@color/bugreport_background"
+ android:padding="@dimen/bug_report_padding"
+ android:visibility="gone"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/bug_report_title_size"
+ android:textColor="@color/bugreport_text"
+ android:gravity="center"
+ android:text="@string/bugreport_dialog_in_progress_title"/>
+ <ProgressBar
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/bug_report_progress_bar_margin_top"
+ android:layout_gravity="center"/>
+ <Button
+ android:id="@+id/button_close"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/bug_report_button_margin_top"
+ android:padding="@dimen/bug_report_secondary_button_padding"
+ android:background="@color/bugreport_button_background"
+ android:textColor="@color/bugreport_button_foreground"
+ android:textSize="@dimen/bug_report_button_text_size"
+ android:text="@string/bugreport_dialog_close"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/BugReportApp/res/layout/bug_report_info_activity.xml b/tests/BugReportApp/res/layout/bug_report_info_activity.xml
new file mode 100644
index 0000000..1cbe9d4
--- /dev/null
+++ b/tests/BugReportApp/res/layout/bug_report_info_activity.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:layout_marginTop="10dp"
+ android:layout_marginLeft="30dp"
+ android:layout_marginRight="30dp">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/info_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/quit_button"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/bugreport_info_quit"
+ style="?android:attr/borderlessButtonStyle" />
+ <Button
+ android:id="@+id/start_bug_report_button"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/bugreport_info_start"
+ style="?android:attr/borderlessButtonStyle" />
+ <TextView
+ android:id="@+id/version_text_view"
+ android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:textSize="14sp"
+ android:gravity="right"
+ android:text="" />
+ </LinearLayout>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_bug_report_info"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/tests/BugReportApp/res/raw/gcs_credentials.json b/tests/BugReportApp/res/raw/gcs_credentials.json
new file mode 100644
index 0000000..1d2bc2b
--- /dev/null
+++ b/tests/BugReportApp/res/raw/gcs_credentials.json
@@ -0,0 +1,6 @@
+{
+ "_0": "Service account credentials for Google Cloud Storage.",
+ "_1": "Please see https://cloud.google.com/iam/docs/creating-managing-service-account-keys",
+ "_2": "to learn how to get credentials.",
+ "_3": "The service account must have 'Storage Object Creator' role."
+}
diff --git a/tests/BugReportApp/res/values/colors.xml b/tests/BugReportApp/res/values/colors.xml
new file mode 100644
index 0000000..1b79cb5
--- /dev/null
+++ b/tests/BugReportApp/res/values/colors.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<resources>
+ <color name="bugreport_background">@*android:color/car_grey_846</color>
+ <color name="bugreport_text">@*android:color/car_body1_light</color>
+
+ <color name="bugreport_button_background">@*android:color/car_grey_746</color>
+ <color name="bugreport_button_foreground">@*android:color/car_body1_light</color>
+</resources>
diff --git a/car-cluster-logging-renderer/res/values/strings.xml b/tests/BugReportApp/res/values/configs.xml
similarity index 68%
rename from car-cluster-logging-renderer/res/values/strings.xml
rename to tests/BugReportApp/res/values/configs.xml
index f36db0d..7dc8914 100644
--- a/car-cluster-logging-renderer/res/values/strings.xml
+++ b/tests/BugReportApp/res/values/configs.xml
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+ 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
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,5 +15,6 @@
limitations under the License.
-->
<resources>
- <string name="app_name">LOGGING_INSTRUMENT_CLUSTER_RENDERER</string>
+ <!-- Google Cloud Storage bucket name where bugreports will be uploaded. -->
+ <string name="config_gcs_bucket" translatable="false"></string>
</resources>
diff --git a/tests/BugReportApp/res/values/dimens.xml b/tests/BugReportApp/res/values/dimens.xml
new file mode 100644
index 0000000..f70b564
--- /dev/null
+++ b/tests/BugReportApp/res/values/dimens.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+<resources>
+
+ <!-- Margin between edge of BugReportActivity dialog and content -->
+ <dimen name="bug_report_padding">30dp</dimen>
+
+ <dimen name="bug_report_title_size">32sp</dimen>
+ <dimen name="bug_report_text_size">24sp</dimen>
+ <dimen name="bug_report_button_text_size">32sp</dimen>
+
+ <!-- VoiceRecordingView dimensions -->
+ <dimen name="bug_report_voice_recording_margin_top">20dp</dimen>
+ <dimen name="bug_report_voice_recording_height">40dp</dimen>
+
+ <!-- Buttons dimensions -->
+ <dimen name="bug_report_button_margin_top">14dp</dimen>
+ <dimen name="bug_report_primary_button_padding">58dp</dimen>
+ <dimen name="bug_report_secondary_button_padding">32dp</dimen>
+
+ <!-- ProgressBar dimensions -->
+ <dimen name="bug_report_progress_bar_margin_top">32dp</dimen>
+
+</resources>
diff --git a/tests/BugReportApp/res/values/strings.xml b/tests/BugReportApp/res/values/strings.xml
new file mode 100644
index 0000000..3f77ab2
--- /dev/null
+++ b/tests/BugReportApp/res/values/strings.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+<resources>
+ <string name="app_name" translatable="false">Bug Report</string>
+
+ <string name="bugreport_info_quit" translatable="false">Close</string>
+ <string name="bugreport_info_start" translatable="false">Start Bug Report</string>
+
+ <string name="bugreport_dialog_submit" translatable="false">Submit</string>
+ <string name="bugreport_dialog_cancel" translatable="false">Cancel</string>
+ <string name="bugreport_dialog_close" translatable="false">Close</string>
+ <string name="bugreport_dialog_title" translatable="false">Speak & Describe The Issue</string>
+ <string name="bugreport_dialog_recording_finished" translatable="false">Recording finished</string>
+ <string name="bugreport_dialog_in_progress_title" translatable="false">A bug report is already being collected</string>
+
+ <string name="toast_permissions_denied" translatable="false">Please grant permissions</string>
+ <string name="toast_bug_report_in_progress" translatable="false">Bug report already being collected</string>
+ <string name="toast_bugreport_cancelled" translatable="false">Bug report is cancelled</string>
+ <string name="toast_timed_out" translatable="false">Timed out, cancelling</string>
+ <string name="toast_status_failed" translatable="false">Bug report failed</string>
+ <string name="toast_status_finished" translatable="false">Bug report finished</string>
+ <string name="toast_status_pending_upload" translatable="false">Bug report ready for upload</string>
+ <string name="toast_status_screencap_failed" translatable="false">Screen capture failed</string>
+ <string name="toast_status_dump_state_failed" translatable="false">Dump state failed</string>
+
+ <!-- Notification strings -->
+ <string name="notification_bugreport_started" translatable="false">Bug report is prepared</string>
+ <string name="notification_bugreport_channel_name" translatable="false">Bug report status channel</string>
+</resources>
diff --git a/tests/BugReportApp/res/values/styles.xml b/tests/BugReportApp/res/values/styles.xml
new file mode 100644
index 0000000..d8dbb02
--- /dev/null
+++ b/tests/BugReportApp/res/values/styles.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<resources>
+ <style name="Theme.Transparent" parent="@android:style/Theme.DeviceDefault.NoActionBar.TranslucentDecor">
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:backgroundDimEnabled">false</item>
+ </style>
+</resources>
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugInfoAdapter.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugInfoAdapter.java
new file mode 100644
index 0000000..fb7c3fa
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugInfoAdapter.java
@@ -0,0 +1,89 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+/**
+ * Adapter class for bug report information
+ */
+public class BugInfoAdapter extends RecyclerView.Adapter<BugInfoAdapter.BugInfoViewHolder> {
+
+ /**
+ * Reference to each bug report info views.
+ */
+ public static class BugInfoViewHolder extends RecyclerView.ViewHolder {
+
+ /** Title view */
+ public TextView titleView;
+
+ /** User view */
+ public TextView userView;
+
+ /** TimeStamp View */
+ public TextView timestampView;
+
+ /** Status View */
+ public TextView statusView;
+
+ /** Message View */
+ public TextView messageView;
+
+ BugInfoViewHolder(View v) {
+ super(v);
+ titleView = itemView.findViewById(R.id.bug_info_row_title);
+ userView = itemView.findViewById(R.id.bug_info_row_user);
+ timestampView = itemView.findViewById(R.id.bug_info_row_timestamp);
+ statusView = itemView.findViewById(R.id.bug_info_row_status);
+ messageView = itemView.findViewById(R.id.bug_info_row_message);
+ }
+ }
+
+ private List<MetaBugReport> mDataset;
+
+ BugInfoAdapter(List<MetaBugReport> dataSet) {
+ mDataset = dataSet;
+ }
+
+ @Override
+ public BugInfoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ // create a new view
+ View v = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.bug_info_view, parent, false);
+ return new BugInfoViewHolder(v);
+ }
+
+ @Override
+ public void onBindViewHolder(BugInfoViewHolder holder, int position) {
+ holder.titleView.setText(mDataset.get(position).getTitle());
+ holder.userView.setText(mDataset.get(position).getUsername());
+ holder.timestampView.setText(mDataset.get(position).getTimestamp());
+ holder.statusView.setText(Status.toString(mDataset.get(position).getStatus()));
+ holder.messageView.setText(mDataset.get(position).getStatusMessage());
+ }
+
+ @Override
+ public int getItemCount() {
+ return mDataset.size();
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java
new file mode 100644
index 0000000..924bda5
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java
@@ -0,0 +1,357 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import static com.google.android.car.bugreport.BugReportService.EXTRA_META_BUG_REPORT;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.media.MediaRecorder;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Random;
+
+/**
+ * Activity that shows two types of dialogs: starting a new bug report and current status of already
+ * in progress bug report.
+ *
+ * <p>If there is no in-progress bug report, it starts recording voice message. After clicking
+ * submit button it initiates {@link BugReportService}.
+ *
+ * <p>If bug report is in-progress, it shows a progress bar.
+ */
+public class BugReportActivity extends Activity {
+ private static final String TAG = BugReportActivity.class.getSimpleName();
+
+ private static final int VOICE_MESSAGE_MAX_DURATION_MILLIS = 60 * 1000;
+ private static final int AUDIO_PERMISSIONS_REQUEST_ID = 1;
+
+ private static final DateFormat BUG_REPORT_TIMESTAMP_DATE_FORMAT =
+ new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ private VoiceRecordingView mVoiceRecordingView;
+ private View mVoiceRecordingFinishedView;
+ private View mSubmitBugReportLayout;
+ private View mInProgressLayout;
+
+ private boolean mBound;
+ private boolean mAudioRecordingStarted;
+ private boolean mBugReportServiceStarted;
+ private BugReportService mService;
+ private MediaRecorder mRecorder;
+ private MetaBugReport mMetaBugReport;
+
+ /** Defines callbacks for service binding, passed to bindService() */
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ BugReportService.ServiceBinder binder = (BugReportService.ServiceBinder) service;
+ mService = binder.getService();
+ mBound = true;
+ startAudioMessageRecording();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName arg0) {
+ // called when service connection breaks unexpectedly.
+ mBound = false;
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.bug_report_activity);
+
+ mVoiceRecordingView = findViewById(R.id.voice_recording_view);
+ mVoiceRecordingFinishedView = findViewById(R.id.voice_recording_finished_text_view);
+ mSubmitBugReportLayout = findViewById(R.id.submit_bug_report_layout);
+ mInProgressLayout = findViewById(R.id.in_progress_layout);
+
+ findViewById(R.id.button_submit).setOnClickListener(this::buttonSubmitClick);
+ findViewById(R.id.button_cancel).setOnClickListener(this::buttonCancelClick);
+ findViewById(R.id.button_close).setOnClickListener(this::buttonCancelClick);
+
+ // Bind to BugReportService.
+ Intent intent = new Intent(this, BugReportService.class);
+ bindService(intent, mConnection, BIND_AUTO_CREATE);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ if (mBound) {
+ startAudioMessageRecording();
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (!mBugReportServiceStarted && mAudioRecordingStarted) {
+ cancelAudioMessageRecording();
+ }
+ mAudioRecordingStarted = false;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ mHandler.removeCallbacksAndMessages(null);
+ if (mBound) {
+ unbindService(mConnection);
+ mBound = false;
+ }
+ }
+
+ private void checkStatus() {
+ if (mBound && mService.isCollectingBugReport()) {
+ scheduleStatusCheck();
+ } else {
+ finish();
+ }
+ }
+
+ private void scheduleStatusCheck() {
+ mHandler.postDelayed(this::checkStatus, 1000);
+ }
+
+ private void showInProgressUi() {
+ mSubmitBugReportLayout.setVisibility(View.GONE);
+ mInProgressLayout.setVisibility(View.VISIBLE);
+ }
+
+ private void showSubmitBugReportUi(boolean isRecording) {
+ mSubmitBugReportLayout.setVisibility(View.VISIBLE);
+ mInProgressLayout.setVisibility(View.GONE);
+ if (isRecording) {
+ mVoiceRecordingFinishedView.setVisibility(View.GONE);
+ mVoiceRecordingView.setVisibility(View.VISIBLE);
+ } else {
+ mVoiceRecordingFinishedView.setVisibility(View.VISIBLE);
+ mVoiceRecordingView.setVisibility(View.GONE);
+ }
+ }
+
+ private void startAudioMessageRecording() {
+ if (mService.isCollectingBugReport()) {
+ Log.i(TAG, "Bug report is already being collected.");
+ showInProgressUi();
+ scheduleStatusCheck();
+ return;
+ }
+
+ if (mAudioRecordingStarted) {
+ Log.i(TAG, "Audio message recording is already started.");
+ return;
+ }
+
+ mAudioRecordingStarted = true;
+ showSubmitBugReportUi(/* isRecording= */ true);
+
+ Date initiatedAt = new Date();
+ String timestamp = BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(initiatedAt);
+ String username = getCurrentUserName();
+ String title = BugReportTitleGenerator.generateBugReportTitle(initiatedAt, username);
+ mMetaBugReport = BugStorageUtils.createBugReport(this, title, timestamp, username);
+
+ if (!hasRecordPermissions()) {
+ requestRecordPermissions();
+ } else {
+ startRecordingWithPermission();
+ }
+ }
+
+ /**
+ * Cancels bugreporting by stopping audio recording and deleting temp files.
+ */
+ private void cancelAudioMessageRecording() {
+ stopAudioRecording();
+ File tempDir = FileUtils.getTempDir(this, mMetaBugReport.getTimestamp());
+ Log.i(TAG, "Bug report is cancelled");
+ new DeleteDirectoryAsyncTask().execute(tempDir);
+ BugStorageUtils.setBugReportStatus(this, mMetaBugReport, Status.STATUS_USER_CANCELLED, "");
+ Toast.makeText(this, getString(R.string.toast_bugreport_cancelled),
+ Toast.LENGTH_SHORT).show();
+ }
+
+ private void buttonCancelClick(View view) {
+ finish();
+ }
+
+ private void buttonSubmitClick(View view) {
+ startBugReportingInService();
+ finish();
+ }
+
+ private void startBugReportingInService() {
+ stopAudioRecording();
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(EXTRA_META_BUG_REPORT, mMetaBugReport);
+ Intent intent = new Intent(this, BugReportService.class);
+ intent.putExtras(bundle);
+ startService(intent);
+ mBugReportServiceStarted = true;
+ }
+
+ private void requestRecordPermissions() {
+ requestPermissions(
+ new String[]{Manifest.permission.RECORD_AUDIO}, AUDIO_PERMISSIONS_REQUEST_ID);
+ }
+
+ private boolean hasRecordPermissions() {
+ return checkSelfPermission(Manifest.permission.RECORD_AUDIO)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ @Override
+ public void onRequestPermissionsResult(
+ int requestCode, String[] permissions, int[] grantResults) {
+ if (requestCode != AUDIO_PERMISSIONS_REQUEST_ID) {
+ return;
+ }
+ for (int i = 0; i < grantResults.length; i++) {
+ if (Manifest.permission.RECORD_AUDIO.equals(permissions[i])
+ && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
+ startRecordingWithPermission();
+ return;
+ }
+ }
+ handleNoPermission(permissions);
+ }
+
+ private void handleNoPermission(String[] permissions) {
+ String text = this.getText(R.string.toast_permissions_denied) + " : "
+ + Arrays.toString(permissions);
+ Log.w(TAG, text);
+ Toast.makeText(this, text, Toast.LENGTH_LONG).show();
+ finish();
+ }
+
+ private void startRecordingWithPermission() {
+ File recordingFile = FileUtils.getFileWithSuffix(this, mMetaBugReport.getTimestamp(),
+ "-message.3gp");
+ Log.d(TAG, "start voice recording: " + recordingFile + ". activityObjectId"
+ + System.identityHashCode(this));
+
+ mRecorder = new MediaRecorder();
+ mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+ mRecorder.setOutputFile(recordingFile);
+
+ try {
+ mRecorder.prepare();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed on MediaRecorder#prepare(), filename: " + recordingFile, e);
+ finish();
+ return;
+ }
+
+ mRecorder.start();
+ mVoiceRecordingView.setRecorder(mRecorder);
+
+ mHandler.postDelayed(() -> {
+ Log.i(TAG, "Timed out while recording voice message, cancelling.");
+ stopAudioRecording();
+ showSubmitBugReportUi(/* isRecording= */ false);
+ }, VOICE_MESSAGE_MAX_DURATION_MILLIS);
+ }
+
+ private void stopAudioRecording() {
+ if (mRecorder != null) {
+ Log.i(TAG, "Recording ended, stopping the MediaRecorder.");
+ mRecorder.stop();
+ mRecorder.release();
+ mRecorder = null;
+ }
+ mVoiceRecordingView.setRecorder(null);
+ }
+
+ private String getCurrentUserName() {
+ UserManager um = UserManager.get(this);
+ return um.getUserName();
+ }
+
+ /** A helper class to generate bugreport title. */
+ private static final class BugReportTitleGenerator {
+ /** Contains easily readable characters. */
+ private static final char[] CHARS_FOR_RANDOM_GENERATOR =
+ new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P',
+ 'R', 'S', 'T', 'U', 'W', 'X', 'Y', 'Z'};
+
+ private static final int LOOKUP_STRING_LENGTH = 6;
+
+ /**
+ * Generates a bugreport title from given timestamp and username.
+ *
+ * <p>Example: "[A45E8] Feedback from user Driver at 2019-09-21_12:00:00"
+ */
+ static String generateBugReportTitle(Date initiatedAt, String username) {
+ // Lookup string is used to search a bug in Buganizer (see b/130915969).
+ String lookupString = generateRandomString(LOOKUP_STRING_LENGTH);
+ String timestamp = BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(initiatedAt);
+ return "[" + lookupString + "] Feedback from user " + username + " at " + timestamp;
+ }
+
+ private static String generateRandomString(int length) {
+ Random random = new Random();
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < length; i++) {
+ int randomIndex = random.nextInt(CHARS_FOR_RANDOM_GENERATOR.length);
+ builder.append(CHARS_FOR_RANDOM_GENERATOR[randomIndex]);
+ }
+ return builder.toString();
+ }
+ }
+
+ /** AsyncTask that recursively deletes directories. */
+ private static class DeleteDirectoryAsyncTask extends AsyncTask<File, Void, Void> {
+ @Override
+ protected Void doInBackground(File... files) {
+ for (File file : files) {
+ Log.d(TAG, "Deleting " + file.getAbsolutePath());
+ FileUtils.deleteDirectory(file);
+ }
+ return null;
+ }
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportInfoActivity.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportInfoActivity.java
new file mode 100644
index 0000000..5fb008a
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportInfoActivity.java
@@ -0,0 +1,117 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import static com.google.android.car.bugreport.PackageUtils.getPackageVersion;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides an activity that provides information on the bugreports that are filed.
+ */
+public class BugReportInfoActivity extends Activity {
+ public static final String TAG = BugReportInfoActivity.class.getSimpleName();
+
+ private RecyclerView mRecyclerView;
+ private RecyclerView.Adapter mAdapter;
+ private RecyclerView.LayoutManager mLayoutManager;
+
+ private static class BugReportInfoTask extends AsyncTask<Void, Void, List<MetaBugReport>> {
+ private final WeakReference<BugReportInfoActivity> mBugReportInfoActivityWeakReference;
+
+ BugReportInfoTask(BugReportInfoActivity activity) {
+ mBugReportInfoActivityWeakReference = new WeakReference<>(activity);
+ }
+
+ @Override
+ protected List<MetaBugReport> doInBackground(Void... voids) {
+ BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
+ if (activity == null) {
+ Log.w(TAG, "Activity is gone, cancelling BugReportInfoTask.");
+ return new ArrayList<>();
+ }
+ return BugStorageUtils.getAllBugReportsDescending(activity);
+ }
+
+ @Override
+ protected void onPostExecute(List<MetaBugReport> result) {
+ BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
+ if (activity == null) {
+ Log.w(TAG, "Activity is gone, cancelling onPostExecute.");
+ return;
+ }
+ activity.mAdapter = new BugInfoAdapter(result);
+ activity.mRecyclerView.setAdapter(activity.mAdapter);
+ activity.mRecyclerView.getAdapter().notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.bug_report_info_activity);
+
+ mRecyclerView = findViewById(R.id.rv_bug_report_info);
+ mRecyclerView.setHasFixedSize(true);
+ // use a linear layout manager
+ mLayoutManager = new LinearLayoutManager(this);
+ mRecyclerView.setLayoutManager(mLayoutManager);
+ mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(),
+ DividerItemDecoration.VERTICAL));
+
+ // specify an adapter (see also next example)
+ mAdapter = new BugInfoAdapter(new ArrayList<>());
+ mRecyclerView.setAdapter(mAdapter);
+
+ findViewById(R.id.quit_button).setOnClickListener(this::onQuitButtonClick);
+ findViewById(R.id.start_bug_report_button).setOnClickListener(
+ this::onStartBugReportButtonClick);
+ ((TextView) findViewById(R.id.version_text_view)).setText(
+ String.format("v%s", getPackageVersion(this)));
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ new BugReportInfoTask(this).execute();
+ }
+
+ private void onQuitButtonClick(View view) {
+ finish();
+ }
+
+ private void onStartBugReportButtonClick(View view) {
+ Intent intent = new Intent(this, BugReportActivity.class);
+ // Clear top is needed, otherwise multiple BugReportActivity-ies get opened and
+ // MediaRecorder crashes.
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java
new file mode 100644
index 0000000..1b1d030
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java
@@ -0,0 +1,413 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import static com.google.android.car.bugreport.PackageUtils.getPackageVersion;
+
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.car.Car;
+import android.car.CarBugreportManager;
+import android.car.CarNotConnectedException;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+import android.view.Display;
+import android.widget.Toast;
+
+import libcore.io.IoUtils;
+
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Service that captures screenshot and bug report using dumpstate and bluetooth snoop logs.
+ *
+ * <p>After collecting all the logs it updates the {@link MetaBugReport} using {@link
+ * BugStorageProvider}, which in turn schedules bug report to upload.
+ */
+public class BugReportService extends Service {
+ private static final String TAG = BugReportService.class.getSimpleName();
+
+ /**
+ * Extra data from intent - current bug report.
+ */
+ static final String EXTRA_META_BUG_REPORT = "meta_bug_report";
+
+ // Wait a short time before starting to capture the bugreport and the screen, so that
+ // bugreport activity can detach from the view tree.
+ // It is ugly to have a timeout, but it is ok here because such a delay should not really
+ // cause bugreport to be tainted with so many other events. If in the future we want to change
+ // this, the best option is probably to wait for onDetach events from view tree.
+ private static final int ACTIVITY_FINISH_DELAY = 1000; //in milliseconds
+
+ private static final String BT_SNOOP_LOG_LOCATION = "/data/misc/bluetooth/logs/btsnoop_hci.log";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final String NOTIFICATION_STATUS_CHANNEL_ID = "BUGREPORT_STATUS_CHANNEL_ID";
+ private static final int BUGREPORT_IN_PROGRESS_NOTIF_ID = 1;
+
+ // http://cs/android/frameworks/base/core/java/android/app/ActivityView.java
+ private static final String ACTIVITY_VIEW_VIRTUAL_DISPLAY = "ActivityViewVirtualDisplay";
+ private static final String OUTPUT_ZIP_FILE = "output_file.zip";
+ private static final String PROGRESS_FILE = "progress.txt";
+
+ private static final String MESSAGE_FAILURE_DUMPSTATE = "Failed to grab dumpstate";
+ private static final String MESSAGE_FAILURE_ZIP = "Failed to zip files";
+
+ // Binder given to clients
+ private final IBinder mBinder = new ServiceBinder();
+
+ private MetaBugReport mMetaBugReport;
+ private NotificationManager mNotificationManager;
+ private NotificationChannel mNotificationChannel;
+ private AtomicBoolean mIsCollectingBugReport = new AtomicBoolean(false);
+ private Handler mHandler;
+ private ScheduledExecutorService mSingleThreadExecutor;
+ private Car mCar;
+ private CarBugreportManager mBugreportManager;
+ private CarBugreportManager.CarBugreportManagerCallback mCallback;
+
+ /**
+ * Client binder.
+ */
+ public class ServiceBinder extends Binder {
+ BugReportService getService() {
+ // Return this instance of LocalService so clients can call public methods
+ return BugReportService.this;
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ mNotificationManager = getSystemService(NotificationManager.class);
+ mNotificationChannel = new NotificationChannel(
+ NOTIFICATION_STATUS_CHANNEL_ID,
+ getString(R.string.notification_bugreport_channel_name),
+ NotificationManager.IMPORTANCE_MIN);
+ mNotificationManager.createNotificationChannel(mNotificationChannel);
+ mHandler = new Handler();
+ mSingleThreadExecutor = Executors.newSingleThreadScheduledExecutor();
+ mCar = Car.createCar(this);
+ try {
+ mBugreportManager = (CarBugreportManager) mCar.getCarManager(Car.CAR_BUGREPORT_SERVICE);
+ } catch (CarNotConnectedException | NoClassDefFoundError e) {
+ Log.w(TAG, "Couldn't get CarBugreportManager", e);
+ }
+ }
+
+ @Override
+ public int onStartCommand(final Intent intent, int flags, int startId) {
+ if (mIsCollectingBugReport.get()) {
+ Log.w(TAG, "bug report is already being collected, ignoring");
+ Toast.makeText(this, R.string.toast_bug_report_in_progress, Toast.LENGTH_SHORT).show();
+ return START_NOT_STICKY;
+ }
+ Log.i(TAG, String.format("Will start collecting bug report, version=%s",
+ getPackageVersion(this)));
+ mIsCollectingBugReport.set(true);
+
+ Notification notification =
+ new Notification.Builder(this, NOTIFICATION_STATUS_CHANNEL_ID)
+ .setContentTitle(getText(R.string.notification_bugreport_started))
+ .setSmallIcon(R.drawable.download_animation)
+ .build();
+ startForeground(BUGREPORT_IN_PROGRESS_NOTIF_ID, notification);
+
+ Bundle extras = intent.getExtras();
+ mMetaBugReport = extras.getParcelable(EXTRA_META_BUG_REPORT);
+
+ collectBugReport();
+
+ // If the service process gets killed due to heavy memory pressure, do not restart.
+ return START_NOT_STICKY;
+ }
+
+ public boolean isCollectingBugReport() {
+ return mIsCollectingBugReport.get();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ private void sendStatusInformation(@StringRes int resId) {
+ // run on ui thread.
+ mHandler.post(() -> Toast.makeText(this, getText(resId), Toast.LENGTH_LONG).show());
+ }
+
+ private void collectBugReport() {
+ // Order is important when capturing. Screenshot should be first
+ mSingleThreadExecutor.schedule(
+ this::takeAllScreenshots, ACTIVITY_FINISH_DELAY, TimeUnit.MILLISECONDS);
+ mSingleThreadExecutor.schedule(
+ this::grabBtSnoopLog, ACTIVITY_FINISH_DELAY, TimeUnit.MILLISECONDS);
+ mSingleThreadExecutor.schedule(
+ this::dumpStateToFile, ACTIVITY_FINISH_DELAY, TimeUnit.MILLISECONDS);
+ }
+
+ private void takeAllScreenshots() {
+ for (int displayId : getAvailableDisplayIds()) {
+ takeScreenshot(displayId);
+ }
+ }
+
+ @Nullable
+ private File takeScreenshot(int displayId) {
+ Log.i(TAG, String.format("takeScreenshot displayId=%d", displayId));
+ File result = FileUtils.getFileWithSuffix(this, mMetaBugReport.getTimestamp(),
+ "-" + displayId + "-screenshot.png");
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "Screen output: " + result.getName());
+ }
+
+ java.lang.Process process = Runtime.getRuntime()
+ .exec("/system/bin/screencap -d " + displayId + " -p "
+ + result.getAbsolutePath());
+
+ // Waits for the command to finish.
+ int err = process.waitFor();
+ if (DEBUG) {
+ Log.d(TAG, "screencap process finished: " + err);
+ }
+ return result;
+ } catch (IOException | InterruptedException e) {
+ Log.e(TAG, "screencap process failed: ", e);
+ sendStatusInformation(R.string.toast_status_screencap_failed);
+ }
+ return null;
+ }
+
+ private List<Integer> getAvailableDisplayIds() {
+ DisplayManager displayManager = getSystemService(DisplayManager.class);
+ ArrayList<Integer> displayIds = new ArrayList<>();
+ for (Display d : displayManager.getDisplays()) {
+ Log.v(TAG,
+ "getAvailableDisplayIds: d.Name=" + d.getName() + ", d.id=" + d.getDisplayId());
+ // We skip virtual displays as they are not captured by screencap.
+ if (d.getName().contains(ACTIVITY_VIEW_VIRTUAL_DISPLAY)) {
+ continue;
+ }
+ displayIds.add(d.getDisplayId());
+ }
+ return displayIds;
+ }
+
+ private void grabBtSnoopLog() {
+ Log.i(TAG, "Grabbing bt snoop log");
+ File result = FileUtils.getFileWithSuffix(this, mMetaBugReport.getTimestamp(),
+ "-btsnoop.bin.log");
+ try {
+ copyBinaryStream(new FileInputStream(new File(BT_SNOOP_LOG_LOCATION)),
+ new FileOutputStream(result));
+ } catch (IOException e) {
+ // this regularly happens when snooplog is not enabled so do not log as an error
+ Log.i(TAG, "Failed to grab bt snooplog, continuing to take bug report.", e);
+ }
+ }
+
+ private void dumpStateToFile() {
+ Log.i(TAG, "Dumpstate to file");
+ File outputFile = FileUtils.getFile(this, mMetaBugReport.getTimestamp(), OUTPUT_ZIP_FILE);
+ File progressFile = FileUtils.getFile(this, mMetaBugReport.getTimestamp(), PROGRESS_FILE);
+
+ ParcelFileDescriptor outFd = null;
+ ParcelFileDescriptor progressFd = null;
+ try {
+ outFd = ParcelFileDescriptor.open(outputFile,
+ ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_READ_WRITE);
+
+ progressFd = ParcelFileDescriptor.open(progressFile,
+ ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_READ_WRITE);
+
+ requestBugReport(outFd, progressFd);
+ } catch (IOException | RuntimeException e) {
+ Log.e(TAG, "Failed to grab dump state", e);
+ BugStorageUtils.setBugReportStatus(this, mMetaBugReport, Status.STATUS_WRITE_FAILED,
+ MESSAGE_FAILURE_DUMPSTATE);
+ sendStatusInformation(R.string.toast_status_dump_state_failed);
+ } finally {
+ IoUtils.closeQuietly(outFd);
+ IoUtils.closeQuietly(progressFd);
+ }
+ }
+
+ // In Android Q and above, use the CarBugreportManager API
+ private void requestBugReport(ParcelFileDescriptor outFd, ParcelFileDescriptor progressFd) {
+ if (DEBUG) {
+ Log.d(TAG, "Requesting a bug report from CarBugReportManager.");
+ }
+ mCallback = new CarBugreportManager.CarBugreportManagerCallback() {
+ @Override
+ public void onError(int errorCode) {
+ Log.e(TAG, "Bugreport failed " + errorCode);
+ sendStatusInformation(R.string.toast_status_failed);
+ // TODO(b/133520419): show this error on Info page or add to zip file.
+ scheduleZipTask();
+ }
+
+ @Override
+ public void onFinished() {
+ Log.i(TAG, "Bugreport finished");
+ scheduleZipTask();
+ }
+ };
+ mBugreportManager.requestZippedBugreport(outFd, progressFd, mCallback);
+ }
+
+ private void scheduleZipTask() {
+ mSingleThreadExecutor.submit(this::zipDirectoryAndScheduleForUpload);
+ }
+
+ private void zipDirectoryAndScheduleForUpload() {
+ try {
+ // When OutputStream from openBugReportFile is closed, BugStorageProvider automatically
+ // schedules an upload job.
+ zipDirectoryToOutputStream(
+ FileUtils.createTempDir(this, mMetaBugReport.getTimestamp()),
+ BugStorageUtils.openBugReportFile(this, mMetaBugReport));
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to zip files", e);
+ BugStorageUtils.setBugReportStatus(this, mMetaBugReport, Status.STATUS_WRITE_FAILED,
+ MESSAGE_FAILURE_ZIP);
+ sendStatusInformation(R.string.toast_status_failed);
+ }
+ mIsCollectingBugReport.set(false);
+ sendStatusInformation(R.string.toast_status_finished);
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DEBUG) {
+ Log.d(TAG, "Service destroyed");
+ }
+ }
+
+ private static void copyBinaryStream(InputStream in, OutputStream out) throws IOException {
+ OutputStream writer = null;
+ InputStream reader = null;
+ try {
+ writer = new DataOutputStream(out);
+ reader = new DataInputStream(in);
+ rawCopyStream(writer, reader);
+ } finally {
+ IoUtils.closeQuietly(reader);
+ IoUtils.closeQuietly(writer);
+ }
+ }
+
+ // does not close the reader or writer.
+ private static void rawCopyStream(OutputStream writer, InputStream reader) throws IOException {
+ int read;
+ byte[] buf = new byte[8192];
+ while ((read = reader.read(buf, 0, buf.length)) > 0) {
+ writer.write(buf, 0, read);
+ }
+ }
+
+ /**
+ * Compresses a directory into a zip file. The method is not recursive. Any sub-directory
+ * contained in the main directory and any files contained in the sub-directories will be
+ * skipped.
+ *
+ * @param dirToZip The path of the directory to zip
+ * @param outStream The output stream to write the zip file to
+ * @throws IOException if the directory does not exist, its files cannot be read, or the output
+ * zip file cannot be written.
+ */
+ private void zipDirectoryToOutputStream(File dirToZip, OutputStream outStream)
+ throws IOException {
+ if (!dirToZip.isDirectory()) {
+ throw new IOException("zip directory does not exist");
+ }
+ Log.v(TAG, "zipping directory " + dirToZip.getAbsolutePath());
+
+ File[] listFiles = dirToZip.listFiles();
+ ZipOutputStream zipStream = new ZipOutputStream(new BufferedOutputStream(outStream));
+ try {
+ for (File file : listFiles) {
+ if (file.isDirectory()) {
+ continue;
+ }
+ String filename = file.getName();
+ if (filename.equals(PROGRESS_FILE)) {
+ // Progress file is already part of zipped bugreport - skip it.
+ continue;
+ }
+ // only for the OUTPUT_FILE, we add invidiual entries to zip file
+ if (filename.equals(OUTPUT_ZIP_FILE)) {
+ extractZippedFileToOutputStream(file, zipStream);
+ } else {
+ FileInputStream reader = new FileInputStream(file);
+ addFileToOutputStream(filename, reader, zipStream);
+ }
+ }
+ } finally {
+ zipStream.close();
+ outStream.close();
+ }
+ // Zipping successful, now cleanup the temp dir.
+ FileUtils.deleteDirectory(dirToZip);
+ }
+
+ private void extractZippedFileToOutputStream(File file, ZipOutputStream zipStream)
+ throws IOException {
+ ZipFile zipFile = new ZipFile(file);
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ InputStream stream = zipFile.getInputStream(entry);
+ addFileToOutputStream(entry.getName(), stream, zipStream);
+ }
+ }
+
+ private void addFileToOutputStream(String filename, InputStream reader,
+ ZipOutputStream zipStream) throws IOException {
+ ZipEntry entry = new ZipEntry(filename);
+ zipStream.putNextEntry(entry);
+ rawCopyStream(zipStream, reader);
+ zipStream.closeEntry();
+ reader.close();
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java
new file mode 100644
index 0000000..b73063a
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java
@@ -0,0 +1,317 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+
+/**
+ * Provides a bug storage interface to save and upload bugreports filed from all users.
+ * In Android Automotive user 0 runs as the system and all the time, while other users won't once
+ * their session ends. This content provider enables bug reports to be uploaded even after
+ * user session ends.
+ */
+public class BugStorageProvider extends ContentProvider {
+ private static final String TAG = BugStorageProvider.class.getSimpleName();
+
+ private static final String AUTHORITY = "com.google.android.car.bugreport";
+ private static final String BUG_REPORTS_TABLE = "bugreports";
+ static final Uri BUGREPORT_CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE);
+
+ static final String COLUMN_ID = "_ID";
+ static final String COLUMN_USERNAME = "username";
+ static final String COLUMN_TITLE = "title";
+ static final String COLUMN_TIMESTAMP = "timestamp";
+ static final String COLUMN_DESCRIPTION = "description";
+ static final String COLUMN_FILEPATH = "filepath";
+ static final String COLUMN_STATUS = "status";
+ static final String COLUMN_STATUS_MESSAGE = "message";
+
+ // URL Matcher IDs.
+ private static final int URL_MATCHED_BUG_REPORTS_URI = 1;
+ private static final int URL_MATCHED_BUG_REPORT_ID_URI = 2;
+
+ private Handler mHandler;
+
+ private DatabaseHelper mDatabaseHelper;
+ private final UriMatcher mUriMatcher;
+
+ /**
+ * A helper class to work with sqlite database.
+ */
+ private static class DatabaseHelper extends SQLiteOpenHelper {
+ private static final String TAG = DatabaseHelper.class.getSimpleName();
+
+ private static final String DATABASE_NAME = "bugreport.db";
+
+ /**
+ * All changes in database versions should be recorded here.
+ * 1: Initial version.
+ */
+ private static final int INITIAL_VERSION = 1;
+ private static final int DATABASE_VERSION = INITIAL_VERSION;
+
+ private static final String CREATE_TABLE = "CREATE TABLE " + BUG_REPORTS_TABLE + " ("
+ + COLUMN_ID + " INTEGER PRIMARY KEY,"
+ + COLUMN_USERNAME + " TEXT,"
+ + COLUMN_TITLE + " TEXT,"
+ + COLUMN_TIMESTAMP + " TEXT NOT NULL,"
+ + COLUMN_DESCRIPTION + " TEXT NULL,"
+ + COLUMN_FILEPATH + " TEXT DEFAULT NULL,"
+ + COLUMN_STATUS + " INTEGER DEFAULT " + Status.STATUS_WRITE_PENDING.getValue() + ","
+ + COLUMN_STATUS_MESSAGE + " TEXT NULL"
+ + ");";
+
+ DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(CREATE_TABLE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.w(TAG, "Upgrading from " + oldVersion + " to " + newVersion);
+ }
+ }
+
+ /** Builds {@link Uri} that points to a bugreport entry with provided bugreport id. */
+ static Uri buildUriWithBugId(int bugReportId) {
+ return Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE + "/" + bugReportId);
+ }
+
+ public BugStorageProvider() {
+ mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ mUriMatcher.addURI(AUTHORITY, BUG_REPORTS_TABLE, URL_MATCHED_BUG_REPORTS_URI);
+ mUriMatcher.addURI(AUTHORITY, BUG_REPORTS_TABLE + "/#", URL_MATCHED_BUG_REPORT_ID_URI);
+ }
+
+ @Override
+ public boolean onCreate() {
+ mDatabaseHelper = new DatabaseHelper(getContext());
+ mHandler = new Handler();
+ return true;
+ }
+
+ @Override
+ public Cursor query(
+ @NonNull Uri uri,
+ @Nullable String[] projection,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs,
+ @Nullable String sortOrder) {
+ return query(uri, projection, selection, selectionArgs, sortOrder, null);
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(
+ @NonNull Uri uri,
+ @Nullable String[] projection,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs,
+ @Nullable String sortOrder,
+ @Nullable CancellationSignal cancellationSignal) {
+ String table;
+ switch (mUriMatcher.match(uri)) {
+ // returns the list of bugreports that match the selection criteria.
+ case URL_MATCHED_BUG_REPORTS_URI:
+ table = BUG_REPORTS_TABLE;
+ break;
+ // returns the bugreport that match the id.
+ case URL_MATCHED_BUG_REPORT_ID_URI:
+ table = BUG_REPORTS_TABLE;
+ if (selection != null || selectionArgs != null) {
+ throw new IllegalArgumentException("selection is not allowed for "
+ + URL_MATCHED_BUG_REPORT_ID_URI);
+ }
+ selection = COLUMN_ID + "=?";
+ selectionArgs = new String[]{ uri.getLastPathSegment() };
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
+ Cursor cursor = db.query(false, table, null, selection, selectionArgs, null, null,
+ sortOrder, null, cancellationSignal);
+ cursor.setNotificationUri(getContext().getContentResolver(), uri);
+ return cursor;
+ }
+
+ @Nullable
+ @Override
+ public String getType(@NonNull Uri uri) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+ String table;
+ if (values == null) {
+ throw new IllegalArgumentException("values cannot be null");
+ }
+ switch (mUriMatcher.match(uri)) {
+ case URL_MATCHED_BUG_REPORTS_URI:
+ table = BUG_REPORTS_TABLE;
+ String filepath = FileUtils.getZipFile(getContext(),
+ (String) values.get(COLUMN_TIMESTAMP),
+ (String) values.get(COLUMN_USERNAME)).getPath();
+ values.put(COLUMN_FILEPATH, filepath);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown uri" + uri);
+ }
+ SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+ long rowId = db.insert(table, null, values);
+ if (rowId > 0) {
+ Uri resultUri = Uri.parse("content://" + AUTHORITY + "/" + table + "/" + rowId);
+ // notify registered content observers
+ getContext().getContentResolver().notifyChange(resultUri, null);
+ return resultUri;
+ }
+ return null;
+ }
+
+ @Override
+ public int delete(
+ @NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
+ switch (mUriMatcher.match(uri)) {
+ // returns the bugreport that match the id.
+ case URL_MATCHED_BUG_REPORT_ID_URI:
+ if (selection != null || selectionArgs != null) {
+ throw new IllegalArgumentException("selection is not allowed for "
+ + URL_MATCHED_BUG_REPORT_ID_URI);
+ }
+ selection = COLUMN_ID + " = ?";
+ selectionArgs = new String[]{uri.getLastPathSegment()};
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
+ return db.delete(BUG_REPORTS_TABLE, selection, selectionArgs);
+ }
+
+ @Override
+ public int update(
+ @NonNull Uri uri,
+ @Nullable ContentValues values,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ if (values == null) {
+ throw new IllegalArgumentException("values cannot be null");
+ }
+ String table;
+ switch (mUriMatcher.match(uri)) {
+ case URL_MATCHED_BUG_REPORTS_URI:
+ table = BUG_REPORTS_TABLE;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+ int rowCount = db.update(table, values, selection, selectionArgs);
+ if (rowCount > 0) {
+ // notify registered content observers
+ getContext().getContentResolver().notifyChange(uri, null);
+ }
+ return rowCount;
+ }
+
+ /**
+ * This is called when the OutputStream is requested by {@link BugStorageUtils#insertBugReport}.
+ *
+ * It expects the file to be a zip file and schedules an upload under the primary user.
+ */
+ @Nullable
+ @Override
+ public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
+ throws FileNotFoundException {
+ if (mUriMatcher.match(uri) != URL_MATCHED_BUG_REPORT_ID_URI) {
+ throw new IllegalArgumentException("unknown uri:" + uri);
+ }
+
+ Cursor c = query(uri, new String[]{COLUMN_FILEPATH}, null, null, null);
+ int count = (c != null) ? c.getCount() : 0;
+ if (count != 1) {
+ // If there is not exactly one result, throw an appropriate
+ // exception.
+ if (c != null) {
+ c.close();
+ }
+ if (count == 0) {
+ throw new FileNotFoundException("No entry for " + uri);
+ }
+ throw new FileNotFoundException("Multiple items at " + uri);
+ }
+
+ c.moveToFirst();
+ int i = c.getColumnIndex(COLUMN_FILEPATH);
+ String path = (i >= 0 ? c.getString(i) : null);
+ c.close();
+ if (path == null) {
+ throw new FileNotFoundException("Column for path not found.");
+ }
+
+ int modeBits = ParcelFileDescriptor.parseMode(mode);
+ try {
+ return ParcelFileDescriptor.open(new File(path), modeBits, mHandler, e -> {
+ Status status;
+ if (e == null) {
+ // success writing the file. Update the field to indicate bugreport
+ // is ready for upload
+ status = Status.STATUS_UPLOAD_PENDING;
+ JobSchedulingUtils.scheduleUploadJob(BugStorageProvider.this.getContext());
+ } else {
+ // We log it and ignore it
+ Log.e(TAG, "Bug report file write failed ", e);
+ status = Status.STATUS_WRITE_FAILED;
+ }
+ SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(COLUMN_STATUS, status.getValue());
+ db.update(BUG_REPORTS_TABLE, values, COLUMN_ID + "=?",
+ new String[]{ uri.getLastPathSegment() });
+ Log.i(TAG, "Finished adding bugreport " + path + " " + uri);
+ });
+ } catch (IOException e) {
+ // An IOException (for example not being able to open the file, will crash us.
+ // That is ok.
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java
new file mode 100644
index 0000000..439e21f
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java
@@ -0,0 +1,278 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_FILEPATH;
+import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_ID;
+import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_STATUS;
+import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_STATUS_MESSAGE;
+import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_TIMESTAMP;
+import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_TITLE;
+import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_USERNAME;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.google.api.client.auth.oauth2.TokenResponseException;
+
+import java.io.FileNotFoundException;
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * A class that hides details when communicating with the bug storage provider.
+ */
+final class BugStorageUtils {
+ private static final String TAG = BugStorageUtils.class.getSimpleName();
+
+ /**
+ * When time/time-zone set incorrectly, Google API returns "400: invalid_grant" error with
+ * description containing this text.
+ */
+ private static final String CLOCK_SKEW_ERROR = "clock with skew to account";
+
+ /** When time/time-zone set incorrectly, Google API returns this error. */
+ private static final String INVALID_GRANT = "invalid_grant";
+
+ private static final DateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
+
+ /**
+ * Creates a new {@link Status#STATUS_WRITE_PENDING} bug report record in a local sqlite
+ * database.
+ *
+ * @param context - an application context.
+ * @param title - title of the bug report.
+ * @param timestamp - timestamp when the bug report was initiated.
+ * @param username - current user name. Note, it's a user name, not an account name.
+ * @return an instance of {@link MetaBugReport} that was created in a database.
+ */
+ @NonNull
+ static MetaBugReport createBugReport(
+ @NonNull Context context,
+ @NonNull String title,
+ @NonNull String timestamp,
+ @NonNull String username) {
+ // insert bug report username and title
+ ContentValues values = new ContentValues();
+ values.put(COLUMN_TITLE, title);
+ values.put(COLUMN_TIMESTAMP, timestamp);
+ values.put(COLUMN_USERNAME, username);
+
+ ContentResolver r = context.getContentResolver();
+ Uri uri = r.insert(BugStorageProvider.BUGREPORT_CONTENT_URI, values);
+
+ Cursor c = r.query(uri, new String[]{COLUMN_ID}, null, null, null);
+ int count = (c == null) ? 0 : c.getCount();
+ if (count != 1) {
+ throw new RuntimeException("Could not create a bug report entry.");
+ }
+ c.moveToFirst();
+ int id = getInt(c, COLUMN_ID);
+ c.close();
+ return new MetaBugReport.Builder(id, timestamp)
+ .setTitle(title)
+ .setUserName(username)
+ .build();
+ }
+
+ /**
+ * Returns a file stream to write the zipped file to. The content provider listens for file
+ * descriptor to be closed, and as soon as it is closed, {@link BugStorageProvider} schedules
+ * it for upload.
+ *
+ * @param context - an application context.
+ * @param metaBugReport - a bug report.
+ * @return a file descriptor where a zip content should be written.
+ */
+ @NonNull
+ static OutputStream openBugReportFile(
+ @NonNull Context context, @NonNull MetaBugReport metaBugReport)
+ throws FileNotFoundException {
+ ContentResolver r = context.getContentResolver();
+
+ // Write the file. When file is closed, bug report record status
+ // will automatically be made ready for uploading.
+ return r.openOutputStream(BugStorageProvider.buildUriWithBugId(metaBugReport.getId()));
+ }
+
+ /**
+ * Deletes {@link MetaBugReport} record from a local database. Returns true if the record was
+ * deleted.
+ *
+ * @param context - an application context.
+ * @param bugReportId - a bug report id.
+ * @return true if the record was deleted.
+ */
+ static boolean deleteBugReport(@NonNull Context context, int bugReportId) {
+ ContentResolver r = context.getContentResolver();
+ return r.delete(BugStorageProvider.buildUriWithBugId(bugReportId), null, null) == 1;
+ }
+
+ /**
+ * Returns bugreports that are waiting to be uploaded.
+ */
+ @NonNull
+ public static List<MetaBugReport> getPendingBugReports(@NonNull Context context) {
+ String selection = COLUMN_STATUS + "=?";
+ String[] selectionArgs = new String[]{
+ Integer.toString(Status.STATUS_UPLOAD_PENDING.getValue())};
+ return getBugreports(context, selection, selectionArgs, null);
+ }
+
+ /**
+ * Returns all bugreports in descending order by the ID field. ID is the index in the
+ * database.
+ */
+ @NonNull
+ public static List<MetaBugReport> getAllBugReportsDescending(@NonNull Context context) {
+ return getBugreports(context, null, null, COLUMN_ID + " DESC");
+ }
+
+ private static List<MetaBugReport> getBugreports(Context context, String selection,
+ String[] selectionArgs, String order) {
+ ArrayList<MetaBugReport> bugReports = new ArrayList<>();
+ String[] projection = {
+ COLUMN_ID,
+ COLUMN_USERNAME,
+ COLUMN_TITLE,
+ COLUMN_TIMESTAMP,
+ COLUMN_FILEPATH,
+ COLUMN_STATUS,
+ COLUMN_STATUS_MESSAGE};
+ ContentResolver r = context.getContentResolver();
+ Cursor c = r.query(BugStorageProvider.BUGREPORT_CONTENT_URI, projection,
+ selection, selectionArgs, order);
+
+ int count = (c != null) ? c.getCount() : 0;
+
+ if (count > 0) c.moveToFirst();
+ for (int i = 0; i < count; i++) {
+ MetaBugReport meta = new MetaBugReport.Builder(getInt(c, COLUMN_ID),
+ getString(c, COLUMN_TIMESTAMP))
+ .setUserName(getString(c, COLUMN_USERNAME))
+ .setTitle(getString(c, COLUMN_TITLE))
+ .setFilepath(getString(c, COLUMN_FILEPATH))
+ .setStatus(getInt(c, COLUMN_STATUS))
+ .setStatusMessage(getString(c, COLUMN_STATUS_MESSAGE))
+ .build();
+ bugReports.add(meta);
+ c.moveToNext();
+ }
+ if (c != null) c.close();
+ return bugReports;
+ }
+
+ /**
+ * returns 0 if the column is not found. Otherwise returns the column value.
+ */
+ private static int getInt(Cursor c, String colName) {
+ int colIndex = c.getColumnIndex(colName);
+ if (colIndex == -1) {
+ Log.w(TAG, "Column " + colName + " not found.");
+ return 0;
+ }
+ return c.getInt(colIndex);
+ }
+
+ /**
+ * returns empty string if the column is not found. Otherwise returns the column value.
+ */
+ private static String getString(Cursor c, String colName) {
+ int colIndex = c.getColumnIndex(colName);
+ if (colIndex == -1) {
+ Log.w(TAG, "Column " + colName + " not found.");
+ return "";
+ }
+ return c.getString(colIndex);
+ }
+
+ /**
+ * Set bugreport status to uploaded successfully.
+ */
+ public static void setUploadSuccess(Context context, MetaBugReport bugReport) {
+ setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_SUCCESS,
+ "Upload time: " + currentTimestamp());
+ }
+
+ /**
+ * Set bugreport status to upload failed.
+ */
+ public static void setUploadFailed(Context context, MetaBugReport bugReport, Exception e) {
+ setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_FAILED, getRootCauseMessage(e));
+ }
+
+ /**
+ * A transient error has occurred. Set bugreport status pending, and update the message
+ * to last exception message.
+ */
+ public static void setUploadRetry(Context context, MetaBugReport bugReport, Exception e) {
+ setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_PENDING,
+ getRootCauseMessage(e));
+ }
+
+ /**
+ * A transient error has occurred. Set bugreport status pending and update the message to
+ * last message.
+ */
+ public static void setUploadRetry(Context context, MetaBugReport bugReport, String msg) {
+ setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_PENDING, msg);
+ }
+
+ /** Gets the root cause of the error. */
+ @NonNull
+ private static String getRootCauseMessage(@Nullable Throwable t) {
+ if (t == null) {
+ return "No error";
+ } else if (t instanceof TokenResponseException) {
+ TokenResponseException ex = (TokenResponseException) t;
+ if (ex.getDetails().getError().equals(INVALID_GRANT)
+ && ex.getDetails().getErrorDescription().contains(CLOCK_SKEW_ERROR)) {
+ return "Auth error. Check if time & time-zone is correct.";
+ }
+ }
+ while (t.getCause() != null) t = t.getCause();
+ return t.getMessage();
+ }
+
+ /** Updates bug report record status. */
+ static void setBugReportStatus(
+ Context context, MetaBugReport bugReport, Status status, String message) {
+ // update status
+ ContentValues values = new ContentValues();
+ values.put(COLUMN_STATUS, status.getValue());
+ if (!TextUtils.isEmpty(message)) {
+ values.put(COLUMN_STATUS_MESSAGE, message);
+ }
+ String where = COLUMN_ID + "=" + bugReport.getId();
+ context.getContentResolver().update(BugStorageProvider.BUGREPORT_CONTENT_URI, values,
+ where, null);
+ }
+
+ private static String currentTimestamp() {
+ return TIMESTAMP_FORMAT.format(new Date());
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/FileUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/FileUtils.java
new file mode 100644
index 0000000..47d05c6
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/FileUtils.java
@@ -0,0 +1,121 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import android.content.Context;
+
+import java.io.File;
+
+/**
+ * File utilities.
+ *
+ * Thread safety and file operations: All file operations should happen on the same worker
+ * thread for thread safety. This is provided by running both bugreport service and file upload
+ * service on a asynctask. Asynctasks are by default executed on the same worker thread in serial.
+ *
+ * There is one exception to the rule above:
+ * Voice recorder works on main thread, however this is not a thread safety problem because:
+ * i. voice recorder always works before starting to collect rest of the bugreport
+ * ii. a bug report cannot be moved to upload (pending) directory before it is completely
+ * collected.
+ */
+public class FileUtils {
+ private static final String PREFIX = "bugreport-";
+ // bug reports waiting to be uploaded
+ private static final String PENDING_DIR = "bug_reports_pending";
+ // temporary directory, used for zipping files
+ private static final String TEMP_DIR = "bug_reports_temp";
+
+ private static final String FS = "@";
+
+ private static File getPendingDir(Context context) {
+ File dir = new File(context.getDataDir(), PENDING_DIR);
+ dir.mkdirs();
+ return dir;
+ }
+
+ /**
+ * Creates and returns file directory for storing bug report files before they are zipped into
+ * a single file.
+ */
+ static File createTempDir(Context context, String timestamp) {
+ File dir = getTempDir(context, timestamp);
+ dir.mkdirs();
+ return dir;
+ }
+
+ /**
+ * Returns path to the directory for storing bug report files before they are zipped into a
+ * single file.
+ */
+ static File getTempDir(Context context, String timestamp) {
+ return new File(context.getDataDir(), TEMP_DIR + "/" + timestamp);
+ }
+
+ /**
+ * Returns zip file directory with the given timestamp and ldap
+ */
+ static File getZipFile(Context context, String timestamp, String ldap) {
+ File zipdir = getPendingDir(context);
+ return new File(zipdir, PREFIX + ldap + FS + timestamp + ".zip");
+ }
+
+ /**
+ * Returns a {@link File} object pointing to a path in a temp directory under current users
+ * {@link Context#getDataDir}.
+ *
+ * @param context - an application context.
+ * @param timestamp - generates file for this timestamp
+ * @param suffix - a filename suffix.
+ * @return A file.
+ */
+ static File getFileWithSuffix(Context context, String timestamp, String suffix) {
+ return new File(createTempDir(context, timestamp), timestamp + suffix);
+ }
+
+ /**
+ * Returns a {@link File} object pointing to a path in a temp directory under current users
+ * {@link Context#getDataDir}.
+ *
+ * @param context - an application context.
+ * @param timestamp - generates file for this timestamp.
+ * @param name - a filename
+ * @return A file.
+ */
+ static File getFile(Context context, String timestamp, String name) {
+ return new File(getTempDir(context, timestamp), name);
+ }
+
+
+ /**
+ * Deletes a directory and its contents recursively
+ *
+ * @param directory to delete
+ */
+ static void deleteDirectory(File directory) {
+ File[] files = directory.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (!file.isDirectory()) {
+ file.delete();
+ } else {
+ deleteDirectory(file);
+ }
+ }
+ }
+ directory.delete();
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java
new file mode 100644
index 0000000..7e8c933
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java
@@ -0,0 +1,61 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.Log;
+
+/**
+ * Utilities for scheduling upload jobs.
+ */
+class JobSchedulingUtils {
+ private static final String TAG = JobSchedulingUtils.class.getSimpleName();
+
+ private static final int UPLOAD_JOB_ID = 1;
+ private static final int RETRY_DELAY_IN_MS = 5_000;
+
+ /**
+ * Schedule an upload job.
+ * 1. require network connectivity
+ * 2. good quality network (large upload size)
+ * 3. persist across reboots
+ */
+ static void scheduleUploadJob(Context context) {
+ JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ if (jobScheduler == null) {
+ Log.w(TAG, "Cannot get JobScheduler from context.");
+ return;
+ }
+
+ JobInfo pendingJob = jobScheduler.getPendingJob(UPLOAD_JOB_ID);
+ // if there is already a pending job, do not schedule a new one.
+ if (pendingJob != null) {
+ Log.d(TAG, "Upload job is already active, not re-scheduling");
+ return;
+ }
+
+ // NOTE: Don't set estimated network bytes, because we want bug reports to be uploaded
+ // without any constraints.
+ jobScheduler.schedule(new JobInfo.Builder(UPLOAD_JOB_ID,
+ new ComponentName(context, UploadJob.class))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .setBackoffCriteria(RETRY_DELAY_IN_MS, JobInfo.BACKOFF_POLICY_LINEAR)
+ .build());
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java b/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java
new file mode 100644
index 0000000..d309303
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java
@@ -0,0 +1,187 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** Represents the information that a bugreport can contain. */
+public final class MetaBugReport implements Parcelable {
+ private final int mId;
+ private final String mTimestamp;
+ private final String mTitle;
+ private final String mUsername;
+ private final String mFilePath;
+ private final int mStatus;
+ private final String mStatusMessage;
+
+ private MetaBugReport(Builder builder) {
+ mId = builder.mId;
+ mTimestamp = builder.mTimestamp;
+ mTitle = builder.mTitle;
+ mUsername = builder.mUsername;
+ mFilePath = builder.mFilePath;
+ mStatus = builder.mStatus;
+ mStatusMessage = builder.mStatusMessage;
+ }
+
+ /**
+ * @return Id of the bug report. Bug report id monotonically increases and is unique.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * @return Username (LDAP) that created this bugreport
+ */
+ public String getUsername() {
+ return mUsername == null ? "" : mUsername;
+ }
+
+ /**
+ * @return Title of the bug.
+ */
+ public String getTitle() {
+ return mTitle == null ? "" : mTitle;
+ }
+
+ /**
+ * @return Timestamp when the bug report is initialized.
+ */
+ public String getTimestamp() {
+ return mTimestamp == null ? "" : mTimestamp;
+ }
+
+ /**
+ * @return path to the zip file
+ */
+ public String getFilePath() {
+ return mFilePath == null ? "" : mFilePath;
+ }
+
+ /**
+ * @return Status of the bug upload.
+ */
+ public int getStatus() {
+ return mStatus;
+ }
+
+ /**
+ * @return StatusMessage of the bug upload.
+ */
+ public String getStatusMessage() {
+ return mStatusMessage == null ? "" : mStatusMessage;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mId);
+ dest.writeString(mTimestamp);
+ dest.writeString(mTitle);
+ dest.writeString(mUsername);
+ dest.writeString(mFilePath);
+ dest.writeInt(mStatus);
+ dest.writeString(mStatusMessage);
+ }
+
+ /** A creator that's used by Parcelable. */
+ public static final Parcelable.Creator<MetaBugReport> CREATOR =
+ new Parcelable.Creator<MetaBugReport>() {
+ public MetaBugReport createFromParcel(Parcel in) {
+ int id = in.readInt();
+ String timestamp = in.readString();
+ String title = in.readString();
+ String username = in.readString();
+ String filePath = in.readString();
+ int status = in.readInt();
+ String statusMessage = in.readString();
+ return new Builder(id, timestamp)
+ .setTitle(title)
+ .setUserName(username)
+ .setFilepath(filePath)
+ .setStatus(status)
+ .setStatusMessage(statusMessage)
+ .build();
+ }
+
+ public MetaBugReport[] newArray(int size) {
+ return new MetaBugReport[size];
+ }
+ };
+
+ /** Builder for MetaBugReport. */
+ public static class Builder {
+ private final int mId;
+ private final String mTimestamp;
+ private String mTitle;
+ private String mUsername;
+ private String mFilePath;
+ private int mStatus;
+ private String mStatusMessage;
+
+ /**
+ * Initializes MetaBugReport.Builder.
+ *
+ * @param id - mandatory bugreport id
+ * @param timestamp - mandatory timestamp when bugreport initialized.
+ */
+ public Builder(int id, String timestamp) {
+ mId = id;
+ mTimestamp = timestamp;
+ }
+
+ /** Sets title. */
+ public Builder setTitle(String title) {
+ mTitle = title;
+ return this;
+ }
+
+ /** Sets username. */
+ public Builder setUserName(String username) {
+ mUsername = username;
+ return this;
+ }
+
+ /** Sets filepath. */
+ public Builder setFilepath(String filePath) {
+ mFilePath = filePath;
+ return this;
+ }
+
+ /** Sets status. */
+ public Builder setStatus(int status) {
+ mStatus = status;
+ return this;
+ }
+
+ /** Sets statusmessage. */
+ public Builder setStatusMessage(String statusMessage) {
+ mStatusMessage = statusMessage;
+ return this;
+ }
+
+ /** Returns a {@link MetaBugReport}. */
+ public MetaBugReport build() {
+ return new MetaBugReport(this);
+ }
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/PackageUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/PackageUtils.java
new file mode 100644
index 0000000..26afc43
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/PackageUtils.java
@@ -0,0 +1,43 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+/**
+ * Package related utility methods.
+ */
+final class PackageUtils {
+ private static final String TAG = PackageUtils.class.getSimpleName();
+
+ /** Returns a BugReport app version name from {@code AndroidManifest.xml}. */
+ static String getPackageVersion(Context context) {
+ try {
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
+ context.getPackageName(), 0);
+ return packageInfo.versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Can't get package version.", e);
+ return "unknown";
+ }
+ }
+
+ private PackageUtils() {
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java b/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java
new file mode 100644
index 0000000..97007b1
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java
@@ -0,0 +1,167 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.google.api.client.extensions.android.http.AndroidHttp;
+import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
+import com.google.api.client.http.HttpResponseException;
+import com.google.api.client.http.HttpTransport;
+import com.google.api.client.http.InputStreamContent;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.google.api.services.storage.Storage;
+import com.google.api.services.storage.model.StorageObject;
+import com.google.common.collect.ImmutableMap;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.net.HttpRetryException;
+import java.net.SocketException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Uploads a file to GCS using a simple (no-multipart / no-resume) upload policy.
+ *
+ * <p>Please see {@code res/values/configs.xml} and {@code res/raw/gcs_credentials.json} for the
+ * configuration.
+ */
+class SimpleUploaderAsyncTask extends AsyncTask<Void, Void, Boolean> {
+ private static final String TAG = SimpleUploaderAsyncTask.class.getSimpleName();
+
+ private static final String ACCESS_SCOPE =
+ "https://www.googleapis.com/auth/devstorage.read_write";
+
+ private static final String STORAGE_METADATA_TITLE = "title";
+
+ private final Context mContext;
+ private final Result mResult;
+
+ /**
+ * The uploader uploads only one bugreport each time it is called. This interface is
+ * used to reschedule upload job, if there are more bugreports waiting.
+ *
+ * Pass true to reschedule upload job, false not to reschedule.
+ */
+ interface Result {
+ void reschedule(boolean s);
+ }
+
+ /** Constructs SimpleUploaderAsyncTask. */
+ SimpleUploaderAsyncTask(@NonNull Context context, @NonNull Result result) {
+ mContext = context;
+ mResult = result;
+ }
+
+ private StorageObject uploadSimple(
+ Storage storage, MetaBugReport bugReport, String fileName, InputStream data)
+ throws IOException {
+ InputStreamContent mediaContent = new InputStreamContent("application/zip", data);
+
+ String bucket = mContext.getString(R.string.config_gcs_bucket);
+ if (TextUtils.isEmpty(bucket)) {
+ throw new RuntimeException("config_gcs_bucket is empty.");
+ }
+
+ // Create GCS MetaData.
+ Map<String, String> metadata = ImmutableMap.of(
+ STORAGE_METADATA_TITLE, bugReport.getTitle()
+ );
+ StorageObject object = new StorageObject()
+ .setBucket(bucket)
+ .setName(fileName)
+ .setMetadata(metadata)
+ .setContentDisposition("attachment");
+ Storage.Objects.Insert insertObject = storage.objects().insert(bucket, object,
+ mediaContent);
+
+ // The media uploader gzips content by default, and alters the Content-Encoding accordingly.
+ // GCS dutifully stores content as-uploaded. This line disables the media uploader behavior,
+ // so the service stores exactly what is in the InputStream, without transformation.
+ insertObject.getMediaHttpUploader().setDisableGZipContent(true);
+ Log.v(TAG, "started uploading object " + fileName + " to bucket " + bucket);
+ return insertObject.execute();
+ }
+
+ private void upload(MetaBugReport bugReport) throws IOException {
+ GoogleCredential credential = GoogleCredential
+ .fromStream(mContext.getResources().openRawResource(R.raw.gcs_credentials))
+ .createScoped(Collections.singleton(ACCESS_SCOPE));
+ Log.v(TAG, "Created credential");
+ HttpTransport httpTransport = AndroidHttp.newCompatibleTransport();
+ JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
+
+ Storage storage = new Storage.Builder(httpTransport, jsonFactory, credential)
+ .setApplicationName("Bugreportupload/1.0").build();
+
+ File bugReportFile = new File(bugReport.getFilePath());
+ String fileName = bugReportFile.getName();
+ try (FileInputStream inputStream = new FileInputStream(bugReportFile)) {
+ StorageObject object = uploadSimple(storage, bugReport, fileName, inputStream);
+ Log.v(TAG, "finished uploading object " + object.getName() + " file " + fileName);
+ }
+ Log.v(TAG, "Deleting file " + fileName);
+ bugReportFile.delete();
+ }
+
+ @Override
+ protected void onPostExecute(Boolean success) {
+ mResult.reschedule(success);
+ }
+
+ /** Returns true is there are more files to upload. */
+ @Override
+ protected Boolean doInBackground(Void... voids) {
+ List<MetaBugReport> bugReports = BugStorageUtils.getPendingBugReports(mContext);
+
+ for (MetaBugReport bugReport : bugReports) {
+ try {
+ if (isCancelled()) {
+ BugStorageUtils.setUploadRetry(mContext, bugReport, "Upload Job Cancelled");
+ return true;
+ }
+ upload(bugReport);
+ BugStorageUtils.setUploadSuccess(mContext, bugReport);
+ } catch (HttpRetryException | HttpResponseException | SocketException
+ | InterruptedIOException e) {
+ Log.e(TAG, String.format("Failed uploading %s - likely a transient error",
+ bugReport.getTimestamp()), e);
+ BugStorageUtils.setUploadRetry(mContext, bugReport, e);
+ } catch (Exception e) {
+ Log.e(TAG,
+ String.format("Failed uploading %s - giving up", bugReport.getTimestamp()),
+ e);
+ BugStorageUtils.setUploadFailed(mContext, bugReport, e);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void onCancelled(Boolean success) {
+ mResult.reschedule(true);
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/StartUpBootReceiver.java b/tests/BugReportApp/src/com/google/android/car/bugreport/StartUpBootReceiver.java
new file mode 100644
index 0000000..abe729a
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/StartUpBootReceiver.java
@@ -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.
+ */
+package com.google.android.car.bugreport;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserManager;
+import android.util.Log;
+
+/**
+ * Handles device boot intents.
+ *
+ * <ul>
+ * <li>Starts {@link UploadJob}</li>
+ * </ul>
+ */
+public class StartUpBootReceiver extends BroadcastReceiver {
+ public static final String TAG = StartUpBootReceiver.class.getSimpleName();
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Run it only once for the system user (u0) and ignore for other users.
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ if (!userManager.isSystemUser()) {
+ return;
+ }
+
+ if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+ Log.d(TAG, "StartUpBootReceiver BOOT_COMPLETED");
+ // We removed "persisted" from UploadJob scheduling, instead we will manually schedule
+ // the job on boot, because "persisted" seems more fragile.
+ JobSchedulingUtils.scheduleUploadJob(context);
+ }
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java b/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java
new file mode 100644
index 0000000..f18baae
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java
@@ -0,0 +1,67 @@
+/*
+ * 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.google.android.car.bugreport;
+
+/** Defines {@link MetaBugReport} statuses. */
+public enum Status {
+ // Bugreport is being written
+ STATUS_WRITE_PENDING(0),
+
+ // Writing bugreport failed
+ STATUS_WRITE_FAILED(1),
+
+ // Bugreport is waiting to be uploaded
+ STATUS_UPLOAD_PENDING(2),
+
+ // Bugreport uploaded successfully
+ STATUS_UPLOAD_SUCCESS(3),
+
+ // Bugreport failed to upload
+ STATUS_UPLOAD_FAILED(4),
+
+ // Bugreport is cancelled by user
+ STATUS_USER_CANCELLED(5);
+
+ private final int mValue;
+
+ Status(int value) {
+ mValue = value;
+ }
+
+ /** Returns integer value of the status. */
+ public int getValue() {
+ return mValue;
+ }
+
+ /** Generates human-readable string from a status value. */
+ public static String toString(int value) {
+ switch (value) {
+ case 0:
+ return "Write Pending";
+ case 1:
+ return "Write failed";
+ case 2:
+ return "Upload pending";
+ case 3:
+ return "Upload success";
+ case 4:
+ return "Upload failed";
+ case 5:
+ return "User cancelled";
+ }
+ return "unknown";
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/SystemUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/SystemUtils.java
new file mode 100644
index 0000000..6a47298
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/SystemUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.car.bugreport;
+
+import android.os.Build;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+/**
+ * Android System utility class.
+ */
+final class SystemUtils {
+ private static final String TAG = SystemUtils.class.getSimpleName();
+
+ private static final String ENFORCING = "Enforcing";
+ private static final String PERMISSIVE = "Permissive";
+
+ private static final String VOLVO_FINGERPRINT_PREFIX = "VolvoCars";
+
+ /**
+ * Returns {@code true} if SELinux is {@code Enforcing}. If it can't verify it returns {@code
+ * true} because most likely SELinux is not allowing running {@code getenforce}.
+ *
+ * <p>Returns {@code false} only when SELinux is {@code Permissive}.
+ */
+ static boolean isSeLinuxEnforcing() {
+ StringBuilder result = new StringBuilder();
+ Process p;
+ try {
+ p = Runtime.getRuntime().exec("getenforce");
+ p.waitFor();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ result.append(line);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "OS does not support getenforce", e);
+ // If getenforce is not available to the device, assume the device is not enforcing
+ return false;
+ }
+ String response = result.toString();
+ if (ENFORCING.equals(response)) {
+ return true;
+ } else if (PERMISSIVE.equals(response)) {
+ return false;
+ } else {
+ Log.e(TAG, "getenforce returned unexpected value, assuming selinux is enforcing!");
+ // If getenforce doesn't return anything, most likely SELinux is in enforcing mode.
+ return true;
+ }
+ }
+
+ /** Returns {@code true} if the app is running on Volvo cars. */
+ static boolean isVolvo() {
+ return Build.FINGERPRINT.startsWith(VOLVO_FINGERPRINT_PREFIX);
+ }
+
+ /** Returns {@code true} if the app is running on Android P. */
+ static boolean isAndroidP() {
+ return Build.VERSION.SDK_INT == Build.VERSION_CODES.P;
+ }
+
+ private SystemUtils() {
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/UploadJob.java b/tests/BugReportApp/src/com/google/android/car/bugreport/UploadJob.java
new file mode 100644
index 0000000..67cc560
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/UploadJob.java
@@ -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 com.google.android.car.bugreport;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.util.Log;
+
+/** Executes a {@link SimpleUploaderAsyncTask}. */
+public class UploadJob extends JobService {
+ private static final String TAG = UploadJob.class.getSimpleName();
+
+ private SimpleUploaderAsyncTask mUploader;
+
+ @Override
+ public boolean onStartJob(final JobParameters jobParameters) {
+ Log.v(TAG, "Starting upload job");
+ mUploader = new SimpleUploaderAsyncTask(
+ this, reschedule -> jobFinished(jobParameters, reschedule));
+ mUploader.execute();
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters jobParameters) {
+ mUploader.cancel(true);
+ return false;
+ }
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/VoiceRecordingView.java b/tests/BugReportApp/src/com/google/android/car/bugreport/VoiceRecordingView.java
new file mode 100644
index 0000000..56d5679
--- /dev/null
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/VoiceRecordingView.java
@@ -0,0 +1,121 @@
+/*
+ * 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.google.android.car.bugreport;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.media.MediaRecorder;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * A view that draws MIC icon and an animated ellipsoid. The ellipsoid animation shows the sound
+ * amplitude from {@link MediaRecorder}.
+ *
+ * <p>All the constant values are chosen experimentally.
+ */
+public class VoiceRecordingView extends View {
+ private static final String TAG = VoiceRecordingView.class.getSimpleName();
+
+ private static final float DROPOFF_STEP = 10f;
+ private static final long ANIMATION_INTERVAL_MS = 70;
+ private static final float RECORDER_AMPLITUDE_NORMALIZER_COEF = 16192.0f;
+
+ private final Paint mPaint;
+ private final BitmapDrawable mMicIconDrawable;
+
+ private float mCurrentRadius;
+ private MediaRecorder mRecorder;
+
+ public VoiceRecordingView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ mMicIconDrawable = (BitmapDrawable) context.getDrawable(
+ android.R.drawable.ic_btn_speak_now);
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setColor(Color.LTGRAY);
+ mPaint.setStyle(Paint.Style.FILL);
+ }
+
+ /** Sets MediaRecorder that will be used to animate the ellipsoid. */
+ public void setRecorder(@Nullable MediaRecorder recorder) {
+ mRecorder = recorder;
+ invalidate();
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldW, int oldH) {
+ super.onSizeChanged(w, h, oldW, oldH);
+
+ float micIconWidth = mMicIconDrawable.getBitmap().getWidth();
+ float micIconHeight = mMicIconDrawable.getBitmap().getHeight();
+ int micIconDrawableWidth = (int) (micIconWidth / micIconHeight * h);
+ int micIconDrawableLeft = (w - micIconDrawableWidth) / 2;
+ mMicIconDrawable.setBounds(
+ new Rect(micIconDrawableLeft, 0, micIconDrawableLeft + micIconDrawableWidth, h));
+ }
+
+ private void updateCurrentRadius(int width) {
+ final float maxRadius = width / 4;
+ float radius = 0;
+
+ if (mRecorder != null) {
+ try {
+ radius += maxRadius * mRecorder.getMaxAmplitude()
+ / RECORDER_AMPLITUDE_NORMALIZER_COEF;
+ } catch (IllegalStateException e) {
+ Log.v(TAG, "Failed to get max amplitude from MediaRecorder");
+ }
+ }
+
+ if (radius > mCurrentRadius) {
+ mCurrentRadius = radius;
+ } else {
+ mCurrentRadius = Math.max(radius, mCurrentRadius - DROPOFF_STEP);
+ }
+ mCurrentRadius = Math.min(maxRadius, mCurrentRadius);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ final int width = canvas.getWidth();
+ final int height = canvas.getHeight();
+
+ updateCurrentRadius(width);
+
+ // Draws an ellipsoid with horizontal radius calculated from MediaRecorder's amplitude.
+ final int mx = width / 2;
+ final int my = height / 2;
+ canvas.drawCircle(mx, my, height / 2, mPaint);
+ canvas.drawCircle(mx - mCurrentRadius, my, height / 2, mPaint);
+ canvas.drawCircle(mx + mCurrentRadius, my, height / 2, mPaint);
+ canvas.drawRect(mx - mCurrentRadius, 0, mx + mCurrentRadius, height, mPaint);
+
+ if (mRecorder != null) {
+ postInvalidateDelayed(ANIMATION_INTERVAL_MS);
+ }
+
+ mMicIconDrawable.draw(canvas);
+ }
+}
diff --git a/tests/DirectRenderingClusterSample/tests/Android.mk b/tests/CarCtsDummyLauncher/Android.mk
similarity index 66%
rename from tests/DirectRenderingClusterSample/tests/Android.mk
rename to tests/CarCtsDummyLauncher/Android.mk
index 9f0a4e8..6382471 100644
--- a/tests/DirectRenderingClusterSample/tests/Android.mk
+++ b/tests/CarCtsDummyLauncher/Android.mk
@@ -1,3 +1,4 @@
+#
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,9 +12,22 @@
# 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.
+#
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-# Include all makefiles in subdirectories
-include $(call all-makefiles-under,$(LOCAL_PATH))
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CarCtsDummyLauncher
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/CarCtsDummyLauncher/AndroidManifest.xml b/tests/CarCtsDummyLauncher/AndroidManifest.xml
new file mode 100644
index 0000000..7f88233
--- /dev/null
+++ b/tests/CarCtsDummyLauncher/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?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"
+ package="com.android.car.dummylauncher">
+
+ <uses-sdk android:minSdkVersion="17" />
+
+ <application
+ android:label="@string/app_name">
+ <activity
+ android:name=".LauncherActivity"
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Material.Light.DarkActionBar"
+ android:launchMode="singleTop">
+ <meta-data android:name="distractionOptimized" android:value="true"/>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.HOME"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+
+
+</manifest>
diff --git a/tests/CarCtsDummyLauncher/res/layout/launcher_activity.xml b/tests/CarCtsDummyLauncher/res/layout/launcher_activity.xml
new file mode 100644
index 0000000..224404f
--- /dev/null
+++ b/tests/CarCtsDummyLauncher/res/layout/launcher_activity.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical|center_horizontal"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/launcher_activity_message" />
+
diff --git a/tests/CarDeveloperOptions/res/xml/trust_agent_settings.xml b/tests/CarCtsDummyLauncher/res/values/strings.xml
similarity index 65%
rename from tests/CarDeveloperOptions/res/xml/trust_agent_settings.xml
rename to tests/CarCtsDummyLauncher/res/values/strings.xml
index da6c9a8..ae9ac11 100644
--- a/tests/CarDeveloperOptions/res/xml/trust_agent_settings.xml
+++ b/tests/CarCtsDummyLauncher/res/values/strings.xml
@@ -14,10 +14,12 @@
limitations under the License.
-->
-<PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:settings="http://schemas.android.com/apk/res-auto"
- android:key="trust_agents"
- android:title="@string/manage_trust_agents"
- settings:controller="com.android.car.developeroptions.security.trustagent.TrustAgentsPreferenceController">
-</PreferenceScreen>
+<resources>
+
+ <string name="launcher_activity_message">Uninstall this after CTS finishs\n\n
+ To uninstall, you can use Setting app or run the following command:\n
+ adb uninstall com.android.car.dummylauncher
+ </string>
+ <string name="app_name">Dummy Launcher for CTS</string>
+
+</resources>
diff --git a/tests/CarCtsDummyLauncher/src/com/android/car/dummylauncher/LauncherActivity.java b/tests/CarCtsDummyLauncher/src/com/android/car/dummylauncher/LauncherActivity.java
new file mode 100644
index 0000000..20fcfc0
--- /dev/null
+++ b/tests/CarCtsDummyLauncher/src/com/android/car/dummylauncher/LauncherActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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.dummylauncher;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+/**
+ * A dummy launcher for CTS.
+ *
+ * Current CarLauncher invokes Maps Activity in its ActivityView and it creates unexpected events
+ * for CTS and they make CTS fail.
+ */
+public class LauncherActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ View view = getLayoutInflater().inflate(R.layout.launcher_activity, null);
+ setContentView(view);
+ }
+}
+
diff --git a/tests/CarDeveloperOptions/res/values-es/strings.xml b/tests/CarDeveloperOptions/res/values-es/strings.xml
index 9c8131b..b2e8581 100644
--- a/tests/CarDeveloperOptions/res/values-es/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-es/strings.xml
@@ -3935,8 +3935,7 @@
<skip />
<!-- no translation found for accessibility_touch_vibration_title (285890135612038092) -->
<skip />
- <!-- no translation found for accessibility_service_master_switch_title (2734791644475782924) -->
- <skip />
+ <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Usar servicio"</string>
<!-- no translation found for accessibility_daltonizer_master_switch_title (4855011639012300777) -->
<skip />
<!-- no translation found for accessibility_caption_master_switch_title (6373335123229234053) -->
diff --git a/tests/CarDeveloperOptions/res/values-or/strings.xml b/tests/CarDeveloperOptions/res/values-or/strings.xml
index 3e19a25..b315f3e 100644
--- a/tests/CarDeveloperOptions/res/values-or/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-or/strings.xml
@@ -4223,8 +4223,7 @@
<skip />
<!-- no translation found for battery_tip_summary_title (2750922152518825526) -->
<skip />
- <!-- no translation found for battery_tip_summary_summary (6294900413896440006) -->
- <skip />
+ <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"ଫୋନର ସାଧାରଣ ବ୍ୟାକଗ୍ରାଉଣ୍ଡ୍ ବ୍ୟାଟେରୀ ବ୍ୟବହାର ରହିଛି"</string>
<!-- no translation found for battery_tip_summary_summary (5280099016800644130) -->
<skip />
<!-- no translation found for battery_tip_summary_summary (4459840492610842705) -->
diff --git a/tests/CarDeveloperOptions/res/values-pt/strings.xml b/tests/CarDeveloperOptions/res/values-pt/strings.xml
index 52e8b5b..f91bfd5 100644
--- a/tests/CarDeveloperOptions/res/values-pt/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pt/strings.xml
@@ -3865,8 +3865,7 @@
<skip />
<!-- no translation found for accessibility_screen_magnification_navbar_configuration_warning (6477234309484795550) -->
<skip />
- <!-- no translation found for accessibility_global_gesture_preference_title (3842279082831426816) -->
- <skip />
+ <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Atalho do volume"</string>
<!-- no translation found for accessibility_shortcut_service_title (3516052294376744060) -->
<skip />
<!-- no translation found for accessibility_shortcut_service_on_lock_screen_title (1279441617927949980) -->
diff --git a/tests/CarDeveloperOptions/res/values-th/strings.xml b/tests/CarDeveloperOptions/res/values-th/strings.xml
index 9c8131b..f4f98b1 100644
--- a/tests/CarDeveloperOptions/res/values-th/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-th/strings.xml
@@ -6702,8 +6702,7 @@
<skip />
<!-- no translation found for launch_by_default (6106985160202769725) -->
<skip />
- <!-- no translation found for app_launch_domain_links_title (2987289657348349133) -->
- <skip />
+ <string name="app_launch_domain_links_title" msgid="2987289657348349133">"การเปิดลิงก์"</string>
<!-- no translation found for app_launch_open_domain_urls_title (8595126859922391331) -->
<skip />
<!-- no translation found for app_launch_open_domain_urls_summary (6803029846855502366) -->
@@ -6794,8 +6793,7 @@
<skip />
<!-- no translation found for tap_to_wake_summary (8485222120721006793) -->
<skip />
- <!-- no translation found for domain_urls_title (7939209950373945367) -->
- <skip />
+ <string name="domain_urls_title" msgid="7939209950373945367">"การเปิดลิงก์"</string>
<!-- no translation found for domain_urls_summary_none (5401203416941265109) -->
<skip />
<!-- no translation found for domain_urls_summary_one (3893975485064803435) -->
diff --git a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
index 9c8131b..0b6bf27 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
@@ -3945,8 +3945,7 @@
<skip />
<!-- no translation found for accessibility_hearingaid_title (3700978781235124891) -->
<skip />
- <!-- no translation found for accessibility_hearingaid_not_connected_summary (634573930469952213) -->
- <skip />
+ <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"無連接任何助聽器"</string>
<!-- no translation found for accessibility_hearingaid_adding_summary (4139031880828714300) -->
<skip />
<!-- no translation found for accessibility_hearingaid_pair_instructions_first_message (2671518890909750740) -->
diff --git a/tests/CarDeveloperOptions/res/xml/security_dashboard_settings.xml b/tests/CarDeveloperOptions/res/xml/security_dashboard_settings.xml
index a797b2d..d10b977 100644
--- a/tests/CarDeveloperOptions/res/xml/security_dashboard_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/security_dashboard_settings.xml
@@ -133,13 +133,6 @@
android:fragment="com.android.car.developeroptions.security.EncryptionAndCredential" />
<Preference
- android:order="70"
- android:key="manage_trust_agents"
- android:title="@string/manage_trust_agents"
- android:summary="@string/summary_placeholder"
- android:fragment="com.android.car.developeroptions.security.trustagent.TrustAgentSettings" />
-
- <Preference
android:order="80"
android:key="screen_pinning_settings"
android:title="@string/screen_pinning_title"
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecurityFeatureProvider.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecurityFeatureProvider.java
index d0872b5..95d601d 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecurityFeatureProvider.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecurityFeatureProvider.java
@@ -19,15 +19,11 @@
import android.content.Context;
import com.android.internal.widget.LockPatternUtils;
-import com.android.car.developeroptions.security.trustagent.TrustAgentManager;
/** FeatureProvider for security. */
public interface SecurityFeatureProvider {
- /** Returns the {@link TrustAgentManager} bound to this {@link SecurityFeatureProvider}. */
- TrustAgentManager getTrustAgentManager();
-
/**
* Returns a {@link LockPatternUtils} instance bound to application context.
*/
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecurityFeatureProviderImpl.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecurityFeatureProviderImpl.java
index 4ea9ece..21df466 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecurityFeatureProviderImpl.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecurityFeatureProviderImpl.java
@@ -19,23 +19,13 @@
import android.content.Context;
import com.android.internal.widget.LockPatternUtils;
-import com.android.car.developeroptions.security.trustagent.TrustAgentManager;
/** Implementation for {@code SecurityFeatureProvider}. */
public class SecurityFeatureProviderImpl implements SecurityFeatureProvider {
- private TrustAgentManager mTrustAgentManager;
private LockPatternUtils mLockPatternUtils;
@Override
- public TrustAgentManager getTrustAgentManager() {
- if (mTrustAgentManager == null) {
- mTrustAgentManager = new TrustAgentManager();
- }
- return mTrustAgentManager;
- }
-
- @Override
public LockPatternUtils getLockPatternUtils(Context context) {
if (mLockPatternUtils == null) {
mLockPatternUtils = new LockPatternUtils(context.getApplicationContext());
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecuritySettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecuritySettings.java
index e866727..5aa22e5 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecuritySettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/SecuritySettings.java
@@ -30,8 +30,6 @@
import com.android.car.developeroptions.dashboard.DashboardFragment;
import com.android.car.developeroptions.enterprise.EnterprisePrivacyPreferenceController;
import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.security.trustagent.ManageTrustAgentsPreferenceController;
-import com.android.car.developeroptions.security.trustagent.TrustAgentListPreferenceController;
import com.android.car.developeroptions.widget.PreferenceCategoryController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -82,10 +80,6 @@
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (use(TrustAgentListPreferenceController.class)
- .handleActivityResult(requestCode, resultCode)) {
- return;
- }
if (use(LockUnificationPreferenceController.class)
.handleActivityResult(requestCode, resultCode, data)) {
return;
@@ -105,12 +99,10 @@
Lifecycle lifecycle, SecuritySettings host) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new EnterprisePrivacyPreferenceController(context));
- controllers.add(new ManageTrustAgentsPreferenceController(context));
controllers.add(new ScreenPinningPreferenceController(context));
controllers.add(new SimLockPreferenceController(context));
controllers.add(new EncryptionStatusPreferenceController(context,
PREF_KEY_ENCRYPTION_SECURITY_PAGE));
- controllers.add(new TrustAgentListPreferenceController(context, host, lifecycle));
final List<AbstractPreferenceController> securityPreferenceControllers = new ArrayList<>();
securityPreferenceControllers.add(new FaceStatusPreferenceController(context));
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/LockAfterTimeoutPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/LockAfterTimeoutPreferenceController.java
index 9805171..79ced0c 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/LockAfterTimeoutPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/LockAfterTimeoutPreferenceController.java
@@ -22,17 +22,14 @@
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Log;
import androidx.preference.Preference;
-import com.android.internal.widget.LockPatternUtils;
import com.android.car.developeroptions.R;
import com.android.car.developeroptions.core.PreferenceControllerMixin;
import com.android.car.developeroptions.display.TimeoutListPreference;
-import com.android.car.developeroptions.overlay.FeatureFactory;
-import com.android.car.developeroptions.security.trustagent.TrustAgentManager;
+import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -44,7 +41,6 @@
private final int mUserId;
private final LockPatternUtils mLockPatternUtils;
- private final TrustAgentManager mTrustAgentManager;
private final DevicePolicyManager mDPM;
public LockAfterTimeoutPreferenceController(Context context, int userId,
@@ -53,8 +49,6 @@
mUserId = userId;
mLockPatternUtils = lockPatternUtils;
mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
- mTrustAgentManager = FeatureFactory.getFactory(context)
- .getSecurityFeatureProvider().getTrustAgentManager();
}
@Override
@@ -137,20 +131,7 @@
best = i;
}
}
-
- final CharSequence trustAgentLabel = mTrustAgentManager
- .getActiveTrustAgentLabel(mContext, mLockPatternUtils);
- if (!TextUtils.isEmpty(trustAgentLabel)) {
- if (Long.valueOf(values[best].toString()) == 0) {
- summary = mContext.getString(R.string.lock_immediately_summary_with_exception,
- trustAgentLabel);
- } else {
- summary = mContext.getString(R.string.lock_after_timeout_summary_with_exception,
- entries[best], trustAgentLabel);
- }
- } else {
- summary = mContext.getString(R.string.lock_after_timeout_summary, entries[best]);
- }
+ summary = mContext.getString(R.string.lock_after_timeout_summary, entries[best]);
}
preference.setSummary(summary);
}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/PowerButtonInstantLockPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/PowerButtonInstantLockPreferenceController.java
index adc7acf..27e1d58 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/PowerButtonInstantLockPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/PowerButtonInstantLockPreferenceController.java
@@ -18,16 +18,13 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
-import android.text.TextUtils;
import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;
-import com.android.internal.widget.LockPatternUtils;
import com.android.car.developeroptions.R;
import com.android.car.developeroptions.core.PreferenceControllerMixin;
-import com.android.car.developeroptions.overlay.FeatureFactory;
-import com.android.car.developeroptions.security.trustagent.TrustAgentManager;
+import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.core.AbstractPreferenceController;
public class PowerButtonInstantLockPreferenceController extends AbstractPreferenceController
@@ -37,15 +34,12 @@
private final int mUserId;
private final LockPatternUtils mLockPatternUtils;
- private final TrustAgentManager mTrustAgentManager;
public PowerButtonInstantLockPreferenceController(Context context, int userId,
LockPatternUtils lockPatternUtils) {
super(context);
mUserId = userId;
mLockPatternUtils = lockPatternUtils;
- mTrustAgentManager = FeatureFactory.getFactory(context)
- .getSecurityFeatureProvider().getTrustAgentManager();
}
@Override
@@ -71,15 +65,7 @@
public void updateState(Preference preference) {
((TwoStatePreference) preference).setChecked(
mLockPatternUtils.getPowerButtonInstantlyLocks(mUserId));
- final CharSequence trustAgentLabel = mTrustAgentManager.getActiveTrustAgentLabel(
- mContext, mLockPatternUtils);
- if (!TextUtils.isEmpty(trustAgentLabel)) {
- preference.setSummary(mContext.getString(
- R.string.lockpattern_settings_power_button_instantly_locks_summary,
- trustAgentLabel));
- } else {
- preference.setSummary(R.string.summary_placeholder);
- }
+ preference.setSummary(R.string.summary_placeholder);
}
@Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/ManageTrustAgentsPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/ManageTrustAgentsPreferenceController.java
deleted file mode 100644
index 6633e34..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/ManageTrustAgentsPreferenceController.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.security.trustagent;
-
-import android.content.Context;
-import android.os.UserHandle;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.core.BasePreferenceController;
-import com.android.car.developeroptions.overlay.FeatureFactory;
-import com.android.car.developeroptions.security.SecurityFeatureProvider;
-
-public class ManageTrustAgentsPreferenceController extends BasePreferenceController {
-
- @VisibleForTesting
- static final String KEY_MANAGE_TRUST_AGENTS = "manage_trust_agents";
- private static final int MY_USER_ID = UserHandle.myUserId();
-
- private final LockPatternUtils mLockPatternUtils;
- private TrustAgentManager mTrustAgentManager;
-
- public ManageTrustAgentsPreferenceController(Context context) {
- super(context, KEY_MANAGE_TRUST_AGENTS);
- final SecurityFeatureProvider securityFeatureProvider = FeatureFactory.getFactory(context)
- .getSecurityFeatureProvider();
- mLockPatternUtils = securityFeatureProvider.getLockPatternUtils(context);
- mTrustAgentManager = securityFeatureProvider.getTrustAgentManager();
- }
-
- @Override
- public int getAvailabilityStatus() {
- return mContext.getResources().getBoolean(R.bool.config_show_manage_trust_agents)
- ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
- }
-
- @Override
- public void updateState(Preference preference) {
- final int numberOfTrustAgent = getTrustAgentCount();
- if (!mLockPatternUtils.isSecure(MY_USER_ID)) {
- preference.setEnabled(false);
- preference.setSummary(R.string.disabled_because_no_backup_security);
- } else if (numberOfTrustAgent > 0) {
- preference.setEnabled(true);
- preference.setSummary(mContext.getResources().getQuantityString(
- R.plurals.manage_trust_agents_summary_on,
- numberOfTrustAgent, numberOfTrustAgent));
- } else {
- preference.setEnabled(true);
- preference.setSummary(R.string.manage_trust_agents_summary);
- }
- }
-
- private int getTrustAgentCount() {
- return mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils).size();
- }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentInfo.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentInfo.java
deleted file mode 100644
index 634935a..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentInfo.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.security.trustagent;
-
-import android.content.ComponentName;
-import android.graphics.drawable.Drawable;
-
-public class TrustAgentInfo implements Comparable<TrustAgentInfo> {
- private final CharSequence mLabel;
- private final ComponentName mComponentName;
- private final Drawable mIcon;
-
- public TrustAgentInfo(CharSequence label, ComponentName componentName, Drawable icon) {
- mLabel = label;
- mComponentName = componentName;
- mIcon = icon;
- }
-
- public CharSequence getLabel() {
- return mLabel;
- }
-
- public ComponentName getComponentName() {
- return mComponentName;
- }
-
- public Drawable getIcon() {
- return mIcon;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof TrustAgentInfo) {
- return mComponentName.equals(((TrustAgentInfo) other).getComponentName());
- }
- return false;
- }
-
- @Override
- public int compareTo(TrustAgentInfo other) {
- return mComponentName.compareTo(other.getComponentName());
- }
-}
\ No newline at end of file
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentListPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentListPreferenceController.java
deleted file mode 100644
index fde9b6c..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentListPreferenceController.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.security.trustagent;
-
-import static com.android.car.developeroptions.security.SecuritySettings.CHANGE_TRUST_AGENT_SETTINGS;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.text.TextUtils;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceScreen;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.core.PreferenceControllerMixin;
-import com.android.car.developeroptions.overlay.FeatureFactory;
-import com.android.car.developeroptions.password.ChooseLockSettingsHelper;
-import com.android.car.developeroptions.security.SecurityFeatureProvider;
-import com.android.car.developeroptions.security.SecuritySettings;
-import com.android.settingslib.RestrictedPreference;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnCreate;
-import com.android.settingslib.core.lifecycle.events.OnResume;
-import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
-
-import java.util.List;
-
-public class TrustAgentListPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin, LifecycleObserver, OnSaveInstanceState,
- OnCreate, OnResume {
-
- private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent";
- @VisibleForTesting
- static final String PREF_KEY_TRUST_AGENT = "trust_agent";
- @VisibleForTesting
- static final String PREF_KEY_SECURITY_CATEGORY = "security_category";
- private static final int MY_USER_ID = UserHandle.myUserId();
-
- private final LockPatternUtils mLockPatternUtils;
- private final TrustAgentManager mTrustAgentManager;
- private final SecuritySettings mHost;
-
- private Intent mTrustAgentClickIntent;
- private PreferenceCategory mSecurityCategory;
-
- public TrustAgentListPreferenceController(Context context, SecuritySettings host,
- Lifecycle lifecycle) {
- super(context);
- final SecurityFeatureProvider provider = FeatureFactory.getFactory(context)
- .getSecurityFeatureProvider();
- mHost = host;
- mLockPatternUtils = provider.getLockPatternUtils(context);
- mTrustAgentManager = provider.getTrustAgentManager();
- if (lifecycle != null) {
- lifecycle.addObserver(this);
- }
- }
-
- @Override
- public boolean isAvailable() {
- return mContext.getResources().getBoolean(R.bool.config_show_trust_agent_click_intent);
- }
-
- @Override
- public String getPreferenceKey() {
- return PREF_KEY_TRUST_AGENT;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mSecurityCategory = screen.findPreference(PREF_KEY_SECURITY_CATEGORY);
- updateTrustAgents();
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- if (savedInstanceState != null
- && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) {
- mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT);
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- if (mTrustAgentClickIntent != null) {
- outState.putParcelable(TRUST_AGENT_CLICK_INTENT, mTrustAgentClickIntent);
- }
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
- return super.handlePreferenceTreeClick(preference);
- }
- final ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(
- mHost.getActivity(), mHost);
- mTrustAgentClickIntent = preference.getIntent();
- boolean confirmationLaunched = helper.launchConfirmationActivity(
- CHANGE_TRUST_AGENT_SETTINGS, preference.getTitle());
-
- if (!confirmationLaunched && mTrustAgentClickIntent != null) {
- // If this returns false, it means no password confirmation is required.
- mHost.startActivity(mTrustAgentClickIntent);
- mTrustAgentClickIntent = null;
- }
- return true;
- }
-
- @Override
- public void onResume() {
- updateTrustAgents();
- }
-
- private void updateTrustAgents() {
- if (mSecurityCategory == null) {
- return;
- }
- // First remove all old trust agents.
- while (true) {
- final Preference oldAgent = mSecurityCategory.findPreference(PREF_KEY_TRUST_AGENT);
- if (oldAgent == null) {
- break;
- } else {
- mSecurityCategory.removePreference(oldAgent);
- }
- }
- // If for some reason the preference is no longer available, don't proceed to add.
- if (!isAvailable()) {
- return;
- }
- // Then add new ones.
- final boolean hasSecurity = mLockPatternUtils.isSecure(MY_USER_ID);
- final List<TrustAgentManager.TrustAgentComponentInfo> agents =
- mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils);
- if (agents == null) {
- return;
- }
- for (TrustAgentManager.TrustAgentComponentInfo agent : agents) {
- final RestrictedPreference trustAgentPreference =
- new RestrictedPreference(mSecurityCategory.getContext());
- trustAgentPreference.setKey(PREF_KEY_TRUST_AGENT);
- trustAgentPreference.setTitle(agent.title);
- trustAgentPreference.setSummary(agent.summary);
- // Create intent for this preference.
- trustAgentPreference.setIntent(new Intent(Intent.ACTION_MAIN)
- .setComponent(agent.componentName));
- trustAgentPreference.setDisabledByAdmin(agent.admin);
- if (!trustAgentPreference.isDisabledByAdmin() && !hasSecurity) {
- trustAgentPreference.setEnabled(false);
- trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
- }
- // Add preference to the settings menu.
- mSecurityCategory.addPreference(trustAgentPreference);
- }
- }
-
- public boolean handleActivityResult(int requestCode, int resultCode) {
- if (requestCode == CHANGE_TRUST_AGENT_SETTINGS && resultCode == Activity.RESULT_OK) {
- if (mTrustAgentClickIntent != null) {
- mHost.startActivity(mTrustAgentClickIntent);
- mTrustAgentClickIntent = null;
- }
- return true;
- }
- return false;
- }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentManager.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentManager.java
deleted file mode 100644
index 9be291e..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentManager.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.security.trustagent;
-
-import static android.service.trust.TrustAgentService.TRUST_AGENT_META_DATA;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.os.UserHandle;
-import android.service.trust.TrustAgentService;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.Xml;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.RestrictedLockUtilsInternal;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-
-/** A manager for trust agent state. */
-public class TrustAgentManager {
-
- // Only allow one trust agent on the platform.
- private static final boolean ONLY_ONE_TRUST_AGENT = false;
-
- public static class TrustAgentComponentInfo {
- public ComponentName componentName;
- public String title;
- public String summary;
- public RestrictedLockUtils.EnforcedAdmin admin = null;
- }
-
- private static final String TAG = "TrustAgentManager";
- private static final Intent TRUST_AGENT_INTENT =
- new Intent(TrustAgentService.SERVICE_INTERFACE);
-
- @VisibleForTesting
- static final String PERMISSION_PROVIDE_AGENT =
- android.Manifest.permission.PROVIDE_TRUST_AGENT;
-
- /**
- * Determines if the service associated with a resolved trust agent intent is allowed to provide
- * trust on this device.
- *
- * @param resolveInfo The entry corresponding to the matched trust agent intent.
- * @param pm The package manager to be used to check for permissions.
- * @return {@code true} if the associated service is allowed to provide a trust agent, and
- * {@code false} if otherwise.
- */
- public boolean shouldProvideTrust(ResolveInfo resolveInfo, PackageManager pm) {
- final String packageName = resolveInfo.serviceInfo.packageName;
- if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
- != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Skipping agent because package " + packageName
- + " does not have permission " + PERMISSION_PROVIDE_AGENT + ".");
- return false;
- }
- return true;
- }
-
- /**
- * Return the display label for active trust agent.
- */
- public CharSequence getActiveTrustAgentLabel(Context context, LockPatternUtils utils) {
- final List<TrustAgentComponentInfo> agents = getActiveTrustAgents(context, utils);
- return agents.isEmpty() ? null : agents.get(0).title;
- }
-
- /**
- * Returns a list of trust agents.
- *
- * If {@link #ONLY_ONE_TRUST_AGENT} is set, the list will contain up to 1 agent instead of all
- * available agents on device.
- */
- public List<TrustAgentComponentInfo> getActiveTrustAgents(Context context,
- LockPatternUtils utils) {
- final int myUserId = UserHandle.myUserId();
- final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
- final PackageManager pm = context.getPackageManager();
- final List<TrustAgentComponentInfo> result = new ArrayList<>();
-
- final List<ResolveInfo> resolveInfos = pm.queryIntentServices(TRUST_AGENT_INTENT,
- PackageManager.GET_META_DATA);
- final List<ComponentName> enabledTrustAgents = utils.getEnabledTrustAgents(myUserId);
- final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal
- .checkIfKeyguardFeaturesDisabled(
- context, DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS, myUserId);
-
- if (enabledTrustAgents != null && !enabledTrustAgents.isEmpty()) {
- for (ResolveInfo resolveInfo : resolveInfos) {
- if (resolveInfo.serviceInfo == null || !shouldProvideTrust(resolveInfo, pm)) {
- continue;
- }
- final TrustAgentComponentInfo trustAgentComponentInfo =
- getSettingsComponent(pm, resolveInfo);
- if (trustAgentComponentInfo.componentName == null ||
- !enabledTrustAgents.contains(getComponentName(resolveInfo)) ||
- TextUtils.isEmpty(trustAgentComponentInfo.title)) {
- continue;
- }
- if (admin != null && dpm.getTrustAgentConfiguration(
- null, getComponentName(resolveInfo)) == null) {
- trustAgentComponentInfo.admin = admin;
- }
- result.add(trustAgentComponentInfo);
- if (ONLY_ONE_TRUST_AGENT) {
- break;
- }
- }
- }
- return result;
- }
-
- public ComponentName getComponentName(ResolveInfo resolveInfo) {
- if (resolveInfo == null || resolveInfo.serviceInfo == null) return null;
- return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
- }
-
- private TrustAgentComponentInfo getSettingsComponent(PackageManager pm,
- ResolveInfo resolveInfo) {
- if (resolveInfo == null || resolveInfo.serviceInfo == null
- || resolveInfo.serviceInfo.metaData == null) {
- return null;
- }
- String cn = null;
- TrustAgentComponentInfo trustAgentComponentInfo = new TrustAgentComponentInfo();
- XmlResourceParser parser = null;
- Exception caughtException = null;
- try {
- parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, TRUST_AGENT_META_DATA);
- if (parser == null) {
- Slog.w(TAG, "Can't find " + TRUST_AGENT_META_DATA + " meta-data");
- return null;
- }
- Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
- AttributeSet attrs = Xml.asAttributeSet(parser);
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && type != XmlPullParser.START_TAG) {
- }
- String nodeName = parser.getName();
- if (!"trust-agent".equals(nodeName)) {
- Slog.w(TAG, "Meta-data does not start with trust-agent tag");
- return null;
- }
- TypedArray sa =
- res.obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent);
- trustAgentComponentInfo.summary =
- sa.getString(com.android.internal.R.styleable.TrustAgent_summary);
- trustAgentComponentInfo.title =
- sa.getString(com.android.internal.R.styleable.TrustAgent_title);
- cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity);
- sa.recycle();
- } catch (PackageManager.NameNotFoundException e) {
- caughtException = e;
- } catch (IOException e) {
- caughtException = e;
- } catch (XmlPullParserException e) {
- caughtException = e;
- } finally {
- if (parser != null) parser.close();
- }
- if (caughtException != null) {
- Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
- return null;
- }
- if (cn != null && cn.indexOf('/') < 0) {
- cn = resolveInfo.serviceInfo.packageName + "/" + cn;
- }
- trustAgentComponentInfo.componentName =
- (cn == null) ? null : ComponentName.unflattenFromString(cn);
- return trustAgentComponentInfo;
- }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentSettings.java
deleted file mode 100644
index b861741..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentSettings.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.security.trustagent;
-
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.provider.SearchIndexableResource;
-
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.dashboard.DashboardFragment;
-import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.settingslib.search.SearchIndexable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SearchIndexable
-public class TrustAgentSettings extends DashboardFragment {
- private static final String TAG = "TrustAgentSettings";
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.TRUST_AGENT;
- }
-
- @Override
- public int getHelpResource() {
- return R.string.help_url_trust_agent;
- }
-
- @Override
- protected String getLogTag() {
- return TAG;
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.trust_agent_settings;
- }
-
- public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider() {
- @Override
- public List<SearchIndexableResource> getXmlResourcesToIndex(
- Context context, boolean enabled) {
- final List<SearchIndexableResource> result = new ArrayList<>();
- final SearchIndexableResource sir = new SearchIndexableResource(context);
- sir.xmlResId = R.xml.trust_agent_settings;
- result.add(sir);
- return result;
- }
- };
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentsPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentsPreferenceController.java
deleted file mode 100644
index 926436b..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/trustagent/TrustAgentsPreferenceController.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.security.trustagent;
-
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.service.trust.TrustAgentService;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.IconDrawableFactory;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.car.developeroptions.core.BasePreferenceController;
-import com.android.car.developeroptions.overlay.FeatureFactory;
-import com.android.car.developeroptions.security.SecurityFeatureProvider;
-import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.android.settingslib.RestrictedSwitchPreference;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-
-import java.util.List;
-
-public class TrustAgentsPreferenceController extends BasePreferenceController
- implements Preference.OnPreferenceChangeListener, LifecycleObserver, OnStart {
-
- private static final Intent TRUST_AGENT_INTENT =
- new Intent(TrustAgentService.SERVICE_INTERFACE);
-
- private final ArrayMap<ComponentName, TrustAgentInfo> mAvailableAgents;
- private final ArraySet<ComponentName> mActiveAgents;
- private final DevicePolicyManager mDevicePolicyManager;
- private final IconDrawableFactory mIconDrawableFactory;
- private final LockPatternUtils mLockPatternUtils;
- private final PackageManager mPackageManager;
- private final TrustAgentManager mTrustAgentManager;
-
- private PreferenceScreen mScreen;
-
- public TrustAgentsPreferenceController(Context context, String key) {
- super(context, key);
- mAvailableAgents = new ArrayMap<>();
- mActiveAgents = new ArraySet<>();
- mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
- mIconDrawableFactory = IconDrawableFactory.newInstance(context);
- final SecurityFeatureProvider securityFeatureProvider =
- FeatureFactory.getFactory(context).getSecurityFeatureProvider();
- mTrustAgentManager = securityFeatureProvider.getTrustAgentManager();
- mLockPatternUtils = securityFeatureProvider.getLockPatternUtils(context);
- mPackageManager = context.getPackageManager();
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mScreen = screen;
- }
-
- @Override
- public int getAvailabilityStatus() {
- return AVAILABLE;
- }
-
- @Override
- public void onStart() {
- updateAgents();
- }
-
- private void updateAgents() {
- findAvailableTrustAgents();
- loadActiveAgents();
- removeUselessExistingPreferences();
-
- final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
- mContext, DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS, UserHandle.myUserId());
-
- for (TrustAgentInfo agent : mAvailableAgents.values()) {
- final ComponentName componentName = agent.getComponentName();
- RestrictedSwitchPreference preference = (RestrictedSwitchPreference)
- mScreen.findPreference(componentName.flattenToString());
- if (preference == null) {
- preference = new RestrictedSwitchPreference(mScreen.getContext());
- }
- preference.setKey(componentName.flattenToString());
- preference.useAdminDisabledSummary(true);
- preference.setTitle(agent.getLabel());
- preference.setIcon(agent.getIcon());
- preference.setOnPreferenceChangeListener(this);
- preference.setChecked(mActiveAgents.contains(componentName));
- if (admin != null && mDevicePolicyManager.getTrustAgentConfiguration(null /* admin */,
- componentName) == null) {
- preference.setChecked(false);
- preference.setDisabledByAdmin(admin);
- }
- mScreen.addPreference(preference);
- }
- }
-
- private void loadActiveAgents() {
- final List<ComponentName> activeTrustAgents = mLockPatternUtils.getEnabledTrustAgents(
- UserHandle.myUserId());
- if (activeTrustAgents != null) {
- mActiveAgents.addAll(activeTrustAgents);
- }
- }
-
- private void saveActiveAgents() {
- mLockPatternUtils.setEnabledTrustAgents(mActiveAgents, UserHandle.myUserId());
- }
-
- private void findAvailableTrustAgents() {
- final List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServices(
- TRUST_AGENT_INTENT, PackageManager.GET_META_DATA);
- mAvailableAgents.clear();
- for (ResolveInfo resolveInfo : resolveInfos) {
- if (resolveInfo.serviceInfo == null) {
- continue;
- }
- if (!mTrustAgentManager.shouldProvideTrust(resolveInfo, mPackageManager)) {
- continue;
- }
- final CharSequence label = resolveInfo.loadLabel(mPackageManager);
- final ComponentName componentName = mTrustAgentManager.getComponentName(resolveInfo);
- final Drawable icon = mIconDrawableFactory.getBadgedIcon(
- resolveInfo.getComponentInfo().applicationInfo);
- final TrustAgentInfo agentInfo = new TrustAgentInfo(label, componentName, icon);
- mAvailableAgents.put(componentName, agentInfo);
- }
- }
-
- private void removeUselessExistingPreferences() {
- final int count = mScreen.getPreferenceCount();
- if (count <= 0) {
- return;
- }
- for (int i = count - 1; i >= 0; i--) {
- final Preference pref = mScreen.getPreference(i);
- final String[] names = TextUtils.split(pref.getKey(), "/");
- final ComponentName componentName = new ComponentName(names[0], names[1]);
- if (!mAvailableAgents.containsKey(componentName)) {
- mScreen.removePreference(pref);
- mActiveAgents.remove(componentName);
- }
- }
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (!(preference instanceof SwitchPreference)) {
- return false;
- }
- for (TrustAgentInfo agent : mAvailableAgents.values()) {
- final ComponentName componentName = agent.getComponentName();
- if (!TextUtils.equals(preference.getKey(), componentName.flattenToString())) {
- continue;
- }
- if ((Boolean) newValue && !mActiveAgents.contains(componentName)) {
- mActiveAgents.add(componentName);
- } else {
- mActiveAgents.remove(componentName);
- }
- saveActiveAgents();
- return true;
- }
- return false;
- }
-}
diff --git a/tests/DirectRenderingClusterSample/Android.mk b/tests/DirectRenderingClusterSample/Android.mk
deleted file mode 100644
index aca5a75..0000000
--- a/tests/DirectRenderingClusterSample/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := DirectRenderingClusterSample
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# Each update should be signed by OEMs
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_JAVA_LIBRARIES += android.car
-LOCAL_STATIC_ANDROID_LIBRARIES += \
- androidx.legacy_legacy-support-v4 \
- androidx-constraintlayout_constraintlayout \
- androidx.car_car-cluster \
- car-arch-common \
- car-media-common \
- car-telephony-common \
- car-apps-common
-
-LOCAL_REQUIRED_MODULES := privapp_whitelist_android.car.cluster.sample
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call all-makefiles-under,$(LOCAL_PATH))
-endif
-
diff --git a/tests/DirectRenderingClusterSample/AndroidManifest.xml b/tests/DirectRenderingClusterSample/AndroidManifest.xml
deleted file mode 100644
index 12c6bba..0000000
--- a/tests/DirectRenderingClusterSample/AndroidManifest.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="android.car.cluster.sample"
- android:sharedUserId="android.uid.system">
-
- <uses-sdk android:targetSdkVersion="25" android:minSdkVersion="25"/>
-
- <!-- We set TYPE_SYSTEM_ALERT window flag to presentation in order
- to show it outside of activity context -->
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
- <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"
- tools:ignore="ProtectedPermissions"/>
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"/>
- <uses-permission android:name="android.permission.INJECT_EVENTS"/>
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
- <!-- Required by 'singleUser' service attribute -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
- <!-- Required by 'startActivityAsUser' -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
- <!-- Required to detect the current user in the device -->
- <uses-permission android:name="android.permission.MANAGE_USERS" />
- <!-- Required to launch navigation apps -->
- <uses-permission android:name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
- <!-- Required to watch activities running on the cluster -->
- <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER"/>
- <!-- Required to show car sensor data -->
- <uses-permission android:name="android.car.permission.CAR_ENERGY"/>
- <uses-permission android:name="android.car.permission.CAR_POWERTRAIN"/>
- <uses-permission android:name="android.car.permission.CAR_INFO"/>
- <uses-permission android:name="android.car.permission.CAR_SPEED"/>
- <uses-permission android:name="android.car.permission.CAR_ENGINE_DETAILED"/>
-
- <application android:label="@string/app_name"
- android:icon="@mipmap/ic_launcher"
- android:directBootAware="true">
- <service android:name=".ClusterRenderingServiceImpl"
- android:exported="false"
- android:singleUser="true"
- android:permission="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
-
- <activity android:name=".MainClusterActivity"
- android:exported="false"
- android:showForAllUsers="true"
- android:theme="@style/Theme.ClusterTheme">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/DirectRenderingClusterSample/res/color/icon_color.xml b/tests/DirectRenderingClusterSample/res/color/icon_color.xml
deleted file mode 100644
index 1ce35ee..0000000
--- a/tests/DirectRenderingClusterSample/res/color/icon_color.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item
- android:color="@color/icon_selected"
- android:state_selected="true"/>
- <item
- android:color="@color/icon_selected"
- android:state_focused="true"/>
- <item
- android:color="@color/icon_unselected"/>
-</selector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_car_info.png b/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_car_info.png
deleted file mode 100644
index adb07d6..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_car_info.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_music.png b/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_music.png
deleted file mode 100644
index f1b2533..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_music.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_nav.png b/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_nav.png
deleted file mode 100644
index 8036b89..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_nav.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_phone.png b/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_phone.png
deleted file mode 100644
index 2daaa8e..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-hdpi/ic_phone.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_car_info.png b/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_car_info.png
deleted file mode 100644
index 9c45d3e..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_car_info.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_music.png b/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_music.png
deleted file mode 100644
index fb0671a..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_music.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_nav.png b/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_nav.png
deleted file mode 100644
index 4844c89..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_nav.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_phone.png b/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_phone.png
deleted file mode 100644
index ef50db6..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-mdpi/ic_phone.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_car_info.png b/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_car_info.png
deleted file mode 100644
index 2db5645..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_car_info.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_music.png b/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_music.png
deleted file mode 100644
index 6154079..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_music.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_nav.png b/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_nav.png
deleted file mode 100644
index f94db1e..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_nav.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_phone.png b/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_phone.png
deleted file mode 100644
index ca0be39..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-xhdpi/ic_phone.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_car_info.png b/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_car_info.png
deleted file mode 100644
index f00be30..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_car_info.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_music.png b/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_music.png
deleted file mode 100644
index 8a875ad..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_music.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_nav.png b/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_nav.png
deleted file mode 100644
index 7b2b514..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_nav.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_phone.png b/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_phone.png
deleted file mode 100644
index fce6fb7..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable-xxhdpi/ic_phone.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable/car_top_view.png b/tests/DirectRenderingClusterSample/res/drawable/car_top_view.png
deleted file mode 100644
index b19ee12..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/car_top_view.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_arrive.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_arrive.xml
deleted file mode 100644
index c83d9f0..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_arrive.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M10,5a2,2,0,1,1,2-2a2,2,0,0,1-2,2Zm4.91284,8.35114l-4.90368-6.342839999999999l-4.903689999999999,6.342839999999999a.38659.38659,0,0,0,.40942.62354l2.95184-1.34375a.35542.35542,0,0,1,.5409600000000001.3690700000000007h-.007690000000000197v5.50006a.49992.49992,0,0,0,.4999400000000005.4999399999999987h1.00012a.49992.49992,0,0,0,.4999399999999987-.4999399999999987v-5.491760000000001h.00916a.35757.35757,0,0,1,.54242-.37738l2.95184,1.34375a.3866.3866,0,0,0,.4094200000000008-.6235300000000006Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_arrive_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_arrive_left.xml
deleted file mode 100644
index 3eba85d..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_arrive_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M3,12a2,2,0,1,1,2-2a2,2,0,0,1-2,2Zm10.00293-.96332a4.05782,4.05782,0,0,1,3.98877,4.07324h.008300000000001972v1.37775a.51232.51232,0,0,0,.5123299999999986.5123299999999986h.97534a.51232.51232,0,0,0,.5123300000000022-.5123299999999986v-1.4876700000000014h-.013850000000001472a6.05607,6.05607,0,0,0-5.9834-5.96332l-.011-.00183l.00012.02008h-.9918700000000005v-.009090000000000487a.35757.35757,0,0,1-.37738-.54242l1.34375-2.95184a.38659.38659,0,0,0-.62354-.40942l-6.342829999999999,4.90368l6.34283,4.90369a.3866.3866,0,0,0,.62354-.40942l-1.34375-2.95184a.35757.35757,0,0,1,.3773800000000005-.5424299999999977v.00909h1"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_arrive_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_arrive_right.xml
deleted file mode 100644
index 0401e8c..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_arrive_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M15,10a2,2,0,1,1,2,2a2,2,0,0,1-2-2Zm-8,1.0549300000000006h1v-.009090000000000487a.35757.35757,0,0,1,.37738.54242l-1.3437500000000009,2.9518400000000007a.3866.3866,0,0,0,.62354.40942l6.34283-4.903680000000001l-6.34283-4.90369a.38659.38659,0,0,0-.62354.40942l1.3437500000000009,2.9518500000000003a.35757.35757,0,0,1-.3773800000000005.5424199999999999v.009090000000000487h-.9918199999999997l.00011999999999989797-.020080000000000098l-.011.00183a6.05607,6.05607,0,0,0-5.98345,5.9633199999999995h-.013849999999999696v1.48767a.51232.51232,0,0,0,.51233.5123299999999986h.9753400000000001a.51232.51232,0,0,0,.51233-.5123299999999986v-1.3777500000000007h.008300000000000196a4.05782,4.05782,0,0,1,3.98877-4.07324"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_arrive_straight.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_arrive_straight.xml
deleted file mode 100644
index c83d9f0..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_arrive_straight.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M10,5a2,2,0,1,1,2-2a2,2,0,0,1-2,2Zm4.91284,8.35114l-4.90368-6.342839999999999l-4.903689999999999,6.342839999999999a.38659.38659,0,0,0,.40942.62354l2.95184-1.34375a.35542.35542,0,0,1,.5409600000000001.3690700000000007h-.007690000000000197v5.50006a.49992.49992,0,0,0,.4999400000000005.4999399999999987h1.00012a.49992.49992,0,0,0,.4999399999999987-.4999399999999987v-5.491760000000001h.00916a.35757.35757,0,0,1,.54242-.37738l2.95184,1.34375a.3866.3866,0,0,0,.4094200000000008-.6235300000000006Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_close.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_close.xml
deleted file mode 100644
index c531094..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_close.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M17.35551,4.05855l-5.589929999999999,5.589929999999999a.49713.49713,0,0,0,0,.703l5.58993,5.58993a.49713.49713,0,0,1,0,.703l-.711.711a.49713.49713,0,0,1-.703,0l-5.58993-5.58993a.49713.49713,0,0,0-.703,0l-5.590030000000002,5.590030000000002a.49713.49713,0,0,1-.703,0l-.711-.711a.49713.49713,0,0,1,0-.703l5.58993-5.58993a.49713.49713,0,0,0,0-.703l-5.589990000000002-5.590030000000002a.49713.49713,0,0,1,0-.703l.711-.711a.49713.49713,0,0,1,.703,0l5.58999,5.5898699999999995a.49713.49713,0,0,0,.703,0l5.58993-5.58993a.49713.49713,0,0,1,.703,0l.711.711a.49713.49713,0,0,1,.00010000000000331966.7030600000000002Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_continue.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_continue.xml
deleted file mode 100644
index 231dac0..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_continue.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M14.50342,8.96637l-2.9518500000000003-1.3437499999999991a.35755.35755,0,0,0-.5424100000000003.3773799999999996v9.49652a.50346.50346,0,0,1-.5034799999999997.5034799999999997h-.993a.50346.50346,0,0,1-.50348-.50348v-9.49652a.35756.35756,0,0,0-.54242-.37738l-2.9518899999999997,1.3437499999999991a.38659.38659,0,0,1-.40942-.62354l4.903689999999999-6.342829999999999l4.90369,6.34283a.3866.3866,0,0,1-.40942999999999863.6235400000000002Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_continue_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_continue_left.xml
deleted file mode 100644
index faa7027..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_continue_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M10,5.97986l.011.00183a6.06019,6.06019,0,0,1,5.989000000000001,6.07324v3.9450699999999994h-.003109999999999502l.002,1.50317a.49614.49614,0,0,1-.49620000000000175.4968299999999992h-1.0064700000000002a.49622.49622,0,0,1-.4962199999999992-.496220000000001v-5.448849999999998a4.05782,4.05782,0,0,0-3.98877-4.07324h-1.99878a.3576.3576,0,0,0-.37738.54248l1.3437500000000009,2.951830000000001a.38659.38659,0,0,1-.62354.40942l-6.34698-4.885420000000002l6.347-4.922a.38659.38659,0,0,1,.62354.40942l-1.3437700000000001,2.9518499999999994a.35757.35757,0,0,0,.37738.54242h1.9875500000000006"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_continue_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_continue_right.xml
deleted file mode 100644
index 6ef4749..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_continue_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M9.98877,7.98169a4.05782,4.05782,0,0,0-3.9887700000000006,4.07324v5.44885a.49622.49622,0,0,1-.4962200000000001.496220000000001h-1.0064700000000002a.49614.49614,0,0,1-.49615-.49683l.0019500000000007844-1.5031700000000008h-.0031100000000003902v-3.9450699999999994a6.06019,6.06019,0,0,1,5.989000000000001-6.07324l.010999999999999233-.0018299999999999983v.0018299999999999983h1.98755a.35757.35757,0,0,0,.37738-.54242l-1.3437500000000018-2.9518400000000007a.38659.38659,0,0,1,.6235300000000006-.40942999999999996l6.346990000000002,4.922000000000001l-6.347,4.88544a.38659.38659,0,0,1-.62354-.40942l1.34375-2.95184a.3576.3576,0,0,0-.37738-.54248h-1.998759999999999Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_depart.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_depart.xml
deleted file mode 100644
index 46c2408..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_depart.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M9.98172,19a2,2,0,1,1,2-2a2,2,0,0,1-2,2Zm4.912840000000001-11.65717l-4.903690000000001-6.342829999999999l-4.90368,6.34283a.38659.38659,0,0,0,.40942.62354l2.95184-1.34375a.35542.35542,0,0,1,.541.36908h-.007730000000000459v5.50006a.49992.49992,0,0,0,.49994.49994h1.00012a.49992.49992,0,0,0,.49994-.49994v-5.491760000000001h.00916a.35757.35757,0,0,1,.54242-.37738l2.95184,1.34375a.3866.3866,0,0,0,.409419999999999-.6235400000000002Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_fork_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_fork_left.xml
deleted file mode 100644
index 8ca9ced..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_fork_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M17.73611,6.57682a.30465.30465,0,0,1,.23032.10507l.649.74859a.30457.30457,0,0,1-.03369.43226l-2.06044,1.7384500000000012a5.4089,5.4089,0,0,0-1.73306,4.29459l.0047,3.60769a.29612.29612,0,0,1-.2961399999999994.2965300000000006h-1.0064700000000002a.29657.29657,0,0,1-.29623-.29622l-.00058-3.47624a6.99129,6.99129,0,0,1,2.269479999999998-5.626159999999999l2.077-1.75275a.30475.30475,0,0,1,.1962-.07182m0-.2a.50269.50269,0,0,0-.32516.119l-2.07704,1.7527300000000006a7.25157,7.25157,0,0,0-2.3398900000000005,5.794459999999999v3.46082a.49622.49622,0,0,0,.496220000000001.4961800000000025h1.0064700000000002a.49614.49614,0,0,0,.49615-.49681l-.0047-3.60767a5.2182,5.2182,0,0,1,1.665-4.14405l2.057410000000001-1.7358700000000002a.50455.50455,0,0,0,.05585-.71613l-.649-.74859a.50345.50345,0,0,0-.38147-.17406h0Zm-8.73542-.39511999999999947h-1.9875500000000006a.35757.35757,0,0,1-.37738-.54242l1.3437499999999991-2.9518400000000007a.38659.38659,0,0,0-.6235399999999993-.40942999999999996l-6.34698,4.922000000000001l6.347,4.88544a.38659.38659,0,0,0,.6235199999999992-.40943999999999825l-1.34375-2.951830000000001a.3576.3576,0,0,1,.37738-.54248h1.9987700000000013a4.05782,4.05782,0,0,1,3.98877,4.07324v5.44885a.49622.49622,0,0,0,.49622999999999884.496220000000001h1.00647a.49614.49614,0,0,0,.49615-.49683l-.001960000000000406-1.5031700000000008h.00311v-3.9450699999999994a6.06019,6.06019,0,0,0-5.989-6.07324l-.011-.00183"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_fork_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_fork_right.xml
deleted file mode 100644
index 9953608..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_fork_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M2.27386,6.57682a.30457.30457,0,0,1,.1961400000000002.07182000000000066l2.0739999999999994,1.7501800000000003a7.00218,7.00218,0,0,1,2.27186,5.644179999999999v3.46088a.29651.29651,0,0,1-.29617999999999967.29612000000000194h-1.0065a.29613.29613,0,0,1-.29618000000000055-.2965699999999991l.003790000000000404-3.5888300000000015a5.42,5.42,0,0,0-1.73517-4.316l-2.0573699999999997-1.7358600000000015a.30461.30461,0,0,1-.03372-.43226l.649-.74859a.30466.30466,0,0,1,.23035-.10507m0-.2a.50345.50345,0,0,0-.38147.17406l-.649.74859a.50458.50458,0,0,0,.05588.71613l2.0573699999999997,1.7358600000000006a5.2182,5.2182,0,0,1,1.665,4.14405l-.0046600000000003305,3.607660000000001a.49617.49617,0,0,0,.49617999999999984.4968299999999992h1.0065a.49616.49616,0,0,0,.49615-.49615v-3.4608500000000006a7.25157,7.25157,0,0,0-2.33983-5.794459999999999l-2.077-1.7527499999999998a.50264.50264,0,0,0-.32516-.119h0Zm8.73442,1.604870000000001h1.98755a.3576.3576,0,0,1,.37738.54248l-1.3437500000000018,2.951830000000001a.38659.38659,0,0,0,.62354.40942l6.34698-4.885420000000002l-6.3469999999999995-4.922000000000001a.38659.38659,0,0,0-.62354.40942l1.34375,2.95184a.35757.35757,0,0,1-.37738.54242h-1.9875299999999996v-.0018199999999986005l-.011.00183a6.06019,6.06019,0,0,0-5.989,6.07324v3.9450699999999994h.003109999999998614l-.002,1.50317a.49614.49614,0,0,0,.4962100000000005.4968299999999992h1.0064599999999997a.49622.49622,0,0,0,.49622-.49622v-5.448849999999998a4.05782,4.05782,0,0,1,3.98877-4.07324h.011229999999999407Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_merge_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_merge_left.xml
deleted file mode 100644
index b8954b8..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_merge_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M7.8,7.2v10.302520000000001a.2978.2978,0,0,1-.2974699999999997.2974800000000002h-1.0050600000000003a.2978.2978,0,0,1-.2974699999999997-.2974800000000002v-10.302520000000001h1.5999999999999996m.20000000000000018-.1999999999999993h-2v10.50252a.49747.49747,0,0,0,.49746999999999986.4974799999999995h1.0050600000000003a.49747.49747,0,0,0,.49746999999999986-.4974799999999995v-10.50252h0Zm-.018309999999999604,3v-1.9875500000000006a.3576.3576,0,0,1,.54248-.37738l2.951830000000001,1.3437500000000009a.38659.38659,0,0,0,.40942-.62354l-4.885420000000002-6.34698l-4.922,6.347a.38659.38659,0,0,0,.40942.62354l2.9518499999999994-1.3437700000000001a.35757.35757,0,0,1,.54242.37738v1.9875500000000006h-.0018299999999991101l.00183.011a6.06019,6.06019,0,0,0,6.07324,5.989000000000001h3.9450699999999994v-.003109999999999502l1.50317.002a.49614.49614,0,0,0,.4968299999999992-.49620000000000175v-1.0064700000000002a.49622.49622,0,0,0-.496220000000001-.4962199999999992h-5.448849999999998a4.05782,4.05782,0,0,1-4.07324-3.98877v-.011229999999999407Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_merge_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_merge_right.xml
deleted file mode 100644
index ab89d03..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_merge_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M13.8,7.2v10.299210000000002a.30112.30112,0,0,1-.30078.3008h-.9984300000000008a.30112.30112,0,0,1-.300790000000001-.30079999999999885v-10.299210000000002h1.6m.20000000000000107-.1999999999999993h-2v10.499210000000001a.50079.50079,0,0,0,.5007900000000003.5007899999999985h.99841a.50079.50079,0,0,0,.5007999999999999-.5007899999999985v-10.499210000000001h0Zm.01831,3v-1.9875500000000006a.35757.35757,0,0,1,.54242-.37738l2.95184,1.34375a.38659.38659,0,0,0,.4094300000000004-.6235299999999988l-4.922000000000001-6.34699l-4.88544,6.347a.38659.38659,0,0,0,.40942.62354l2.95184-1.34375a.3576.3576,0,0,1,.54248.37738v1.99878a4.05782,4.05782,0,0,1-4.0732300000000015,3.9887499999999996h-5.44885a.49622.49622,0,0,0-.4962200000000001.4962199999999992v1.00647a.49614.49614,0,0,0,.49683.49615l1.50317-.001949999999999008v.003109999999999502h3.9450700000000003a6.06019,6.06019,0,0,0,6.07324-5.989l.0018299999999999983-.010999999999999233"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_new_name_straight.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_new_name_straight.xml
deleted file mode 100644
index 231dac0..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_new_name_straight.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M14.50342,8.96637l-2.9518500000000003-1.3437499999999991a.35755.35755,0,0,0-.5424100000000003.3773799999999996v9.49652a.50346.50346,0,0,1-.5034799999999997.5034799999999997h-.993a.50346.50346,0,0,1-.50348-.50348v-9.49652a.35756.35756,0,0,0-.54242-.37738l-2.9518899999999997,1.3437499999999991a.38659.38659,0,0,1-.40942-.62354l4.903689999999999-6.342829999999999l4.90369,6.34283a.3866.3866,0,0,1-.40942999999999863.6235400000000002Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_left.xml
deleted file mode 100644
index 536fd22..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M14.5029,2.2a.29744.29744,0,0,1,.29710000000000036.2971199999999996v15.005760000000002a.29744.29744,0,0,1-.29710000000000036.2971199999999996h-1.0058000000000007a.29744.29744,0,0,1-.29710000000000036-.2971199999999996v-15.005760000000002a.29744.29744,0,0,1,.29710000000000036-.2971199999999987h1.0058m0-.2h-1.0058000000000007a.49711.49711,0,0,0-.49709999999999965.4971199999999998v15.005760000000002a.49711.49711,0,0,0,.49709999999999965.4971199999999989h1.0058a.49711.49711,0,0,0,.49709999999999965-.4971199999999989v-15.005760000000002a.49711.49711,0,0,0-.49709999999999965-.4971199999999989h0Zm-5.50212,3.9816900000000004h-1.9875500000000006a.35757.35757,0,0,1-.37738-.54242l1.3437499999999991-2.9518400000000007a.38659.38659,0,0,0-.6235399999999993-.40942999999999996l-6.34698,4.922000000000001l6.347,4.88544a.38659.38659,0,0,0,.6235199999999992-.40943999999999825l-1.34375-2.951830000000001a.3576.3576,0,0,1,.37738-.54248h1.9987700000000013a4.05782,4.05782,0,0,1,3.98877,4.07324v5.44885a.49622.49622,0,0,0,.49622999999999884.496220000000001h1.00647a.49614.49614,0,0,0,.49615-.49683l-.001960000000000406-1.5031700000000008h.00311v-3.9450699999999994a6.06019,6.06019,0,0,0-5.989-6.07324l-.011-.00183"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_right.xml
deleted file mode 100644
index 3048587..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M6.5029,2.2a.29744.29744,0,0,1,.2970999999999995.2971199999999996v15.005760000000002a.29744.29744,0,0,1-.2970999999999995.2971199999999996h-1.0058000000000007a.29744.29744,0,0,1-.2970999999999995-.2971199999999996v-15.005760000000002a.29744.29744,0,0,1,.2970999999999995-.2971199999999987h1.0058000000000007m0-.2h-1.0058000000000007a.49711.49711,0,0,0-.49709999999999965.4971199999999998v15.005760000000002a.49711.49711,0,0,0,.49709999999999965.4971199999999989h1.0058000000000007a.49711.49711,0,0,0,.49709999999999965-.4971199999999989v-15.005760000000002a.49711.49711,0,0,0-.49709999999999965-.4971199999999989h0Zm4.5054,5.98169h1.98755a.3576.3576,0,0,1,.37738.54248l-1.3437500000000018,2.951830000000001a.38659.38659,0,0,0,.62354.40942l6.34698-4.885420000000002l-6.3469999999999995-4.922000000000001a.38659.38659,0,0,0-.62354.40942l1.34375,2.95184a.35757.35757,0,0,1-.37738.54242h-1.9875299999999996v-.0018199999999986005l-.011.00183a6.06019,6.06019,0,0,0-5.989,6.07324v3.9450699999999994h.003109999999998614l-.002,1.50317a.49614.49614,0,0,0,.4962100000000005.4968299999999992h1.0064599999999997a.49622.49622,0,0,0,.49622-.49622v-5.448849999999998a4.05782,4.05782,0,0,1,3.98877-4.07324h.011229999999999407Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_slight_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_slight_left.xml
deleted file mode 100644
index 91ffc9c..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_slight_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M14.5029,2.2a.29744.29744,0,0,1,.29710000000000036.2971199999999996v15.005760000000002a.29744.29744,0,0,1-.29710000000000036.2971199999999996h-1.0058000000000007a.29744.29744,0,0,1-.29710000000000036-.2971199999999996v-15.005760000000002a.29744.29744,0,0,1,.29710000000000036-.2971199999999987h1.0058m0-.2h-1.0058000000000007a.49711.49711,0,0,0-.49709999999999965.4971199999999998v15.005760000000002a.49711.49711,0,0,0,.49709999999999965.4971199999999989h1.0058a.49711.49711,0,0,0,.49709999999999965-.4971199999999989v-15.005760000000002a.49711.49711,0,0,0-.49709999999999965-.4971199999999989h0Zm-1.85684,6.24854l-2.457460000000001-2.07386a.3576.3576,0,0,1,.07019-.6571l2.9489100000000015-1.3501600000000007a.38658.38658,0,0,0-.20294-.71777l-8.004760000000001-.4496500000000001l1.58044,7.86a.38663.38663,0,0,0,.73938.09912l.9181799999999996-3.1106099999999985a.35758.35758,0,0,1,.6405-.16266l2.44818,2.06561a5.21819,5.21819,0,0,1,1.665,4.144l-.0047,3.60767a.49614.49614,0,0,0,.49624000000000024.49687000000000126h1.00653a.49621.49621,0,0,0,.49615-.49622v-3.4607799999999997a7.25157,7.25157,0,0,0-2.339839999999999-5.794459999999999Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_slight_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_slight_right.xml
deleted file mode 100644
index b549937..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_off_ramp_slight_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M8.5029,2.2a.29744.29744,0,0,1,.29710000000000036.2971199999999996v15.005760000000002a.29744.29744,0,0,1-.29710000000000036.2971199999999996h-1.0058000000000007a.29744.29744,0,0,1-.2970999999999995-.2971199999999996v-15.005760000000002a.29744.29744,0,0,1,.2970999999999995-.2971199999999987h1.0058000000000007m0-.2h-1.0058000000000007a.49711.49711,0,0,0-.49709999999999965.4971199999999998v15.005760000000002a.49711.49711,0,0,0,.49709999999999965.4971199999999989h1.0058000000000007a.49711.49711,0,0,0,.49709999999999965-.4971199999999989v-15.005760000000002a.49711.49711,0,0,0-.49709999999999965-.4971199999999989h0Zm-1.4888000000000003,12.043v3.46082a.49621.49621,0,0,0,.4961500000000001.4961800000000025h1.0065300000000006a.49614.49614,0,0,0,.49615-.49683l-.0047-3.60767a5.21819,5.21819,0,0,1,1.665-4.144l2.44818-2.06561a.35758.35758,0,0,1,.6405.16266l.91821,3.1106a.38663.38663,0,0,0,.7394400000000001-.09915000000000163l1.5804399999999994-7.859999999999999l-8.00476.44965a.38658.38658,0,0,0-.20294.71777l2.94891,1.35016a.3576.3576,0,0,1,.07019.6571l-2.457460000000001,2.0738600000000007a7.25157,7.25157,0,0,0-2.3398399999999997,5.794459999999999Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_left.xml
deleted file mode 100644
index 65e66e2..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M9.00078,5.97986l.011.00183a6.06019,6.06019,0,0,1,5.989,6.07324v3.9450699999999994h-.0031199999999991235l.002,1.50317a.49614.49614,0,0,1-.4962.4968299999999992h-1.0064600000000006a.49622.49622,0,0,1-.49622-.49622v-5.448849999999998a4.05782,4.05782,0,0,0-3.98878-4.07324h-1.9987700000000004a.3576.3576,0,0,0-.37738.54248l1.3437499999999991,2.951830000000001a.38659.38659,0,0,1-.62354.40942l-6.346979999999999-4.885420000000002l6.347-4.922a.38659.38659,0,0,1,.62354.40942l-1.343770000000001,2.9518499999999994a.35757.35757,0,0,0,.37738.54242h1.9875500000000015"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_right.xml
deleted file mode 100644
index 1647927..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M10.99707,7.98169a4.05782,4.05782,0,0,0-3.9887700000000006,4.07324v5.44885a.49622.49622,0,0,1-.4962200000000001.496220000000001h-1.0064599999999997a.49614.49614,0,0,1-.49615-.49683l.0019399999999993867-1.5031700000000008h-.003109999999999502v-3.9450699999999994a6.06019,6.06019,0,0,1,5.989-6.07324l.011-.00183v.0018299999999999983h1.98755a.35757.35757,0,0,0,.37738-.54242l-1.34375-2.9518400000000007a.38659.38659,0,0,1,.623520000000001-.40942999999999996l6.3469999999999995,4.922000000000001l-6.347,4.88544a.38659.38659,0,0,1-.62354-.40942l1.34375-2.95184a.3576.3576,0,0,0-.37738-.54248h-1.9987599999999972Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_sharp_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_sharp_left.xml
deleted file mode 100644
index 83b821a..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_sharp_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M15.49771,18a.49779.49779,0,0,1-.49779-.49779v-12.4983l-.27979-.00635a2.56758,2.56758,0,0,0-2.0957.79l-5.39526,4.61285a.34918.34918,0,0,0,.08252.63177l2.92877,1.39331a.38658.38658,0,0,1-.21344.71472l-8.0105.33209l1.69568-7.836a.38661.38661,0,0,1,.74072-.0882l.8725,3.12372a.35757.35757,0,0,0,.638.17206l.0037800000000007827.00446999999999953l5.392099999999999-4.60909a4.46634,4.46634,0,0,1,3.38476-1.2412599999999996l.2641600000000004.0019999999999997797a1.92935,1.92935,0,0,1,1.43408.56885a2.10247,2.10247,0,0,1,.55713,1.46045l.00046999999999997044,12.47289a.49779.49779,0,0,1-.49779000000000195.4978100000000012h-1.0044Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_sharp_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_sharp_right.xml
deleted file mode 100644
index 3394364..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_sharp_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M3.49789,17.99542a.49779.49779,0,0,1-.49779-.49781l.00047000000000041453-12.472889999999998a2.10247,2.10247,0,0,1,.5571299999999999-1.4604500000000002a1.92935,1.92935,0,0,1,1.43408-.56885l.26416-.002a4.46634,4.46634,0,0,1,3.38476,1.2412599999999996l5.392099999999999,4.609089999999999l.00378-.00446a.35757.35757,0,0,0,.638-.17206l.8725-3.12372a.38661.38661,0,0,1,.74072.0882l1.69568,7.836l-8.01048-.3320899999999991a.38658.38658,0,0,1-.21344-.71472l2.92877-1.39331a.34918.34918,0,0,0,.08252-.63177l-5.395280000000001-4.612840000000001a2.56758,2.56758,0,0,0-2.0957-.79l-.27979.00635v12.4983a.49779.49779,0,0,1-.49779.49779h-1.0043999999999995Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_slight_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_slight_left.xml
deleted file mode 100644
index 385a519..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_slight_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M12.9859,14.043v3.46082a.49621.49621,0,0,1-.4961500000000001.4961800000000025h-1.0065300000000015a.49614.49614,0,0,1-.49615-.49683l.0047-3.60767a5.21819,5.21819,0,0,0-1.665-4.144l-2.4482299999999997-2.0656499999999998a.35758.35758,0,0,0-.6405.16266l-.91821,3.1106a.38663.38663,0,0,1-.7393899999999993-.09910999999999959l-1.5804400000000003-7.859999999999999l8.00476.44965a.38658.38658,0,0,1,.20294.71777l-2.9489099999999997,1.3501599999999998a.3576.3576,0,0,0-.07019.6571l2.45746,2.07385a7.25157,7.25157,0,0,1,2.3398400000000024,5.7944700000000005Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_slight_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_slight_right.xml
deleted file mode 100644
index 2ee993c..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_on_ramp_slight_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M9.35394,8.24854l2.457460000000001-2.07386a.3576.3576,0,0,0-.07019-.6571l-2.9489100000000015-1.3501600000000007a.38658.38658,0,0,1,.20294-.71777l8.004760000000001-.4496500000000001l-1.58044,7.86a.38663.38663,0,0,1-.73938.09912l-.9181799999999996-3.1106099999999985a.35758.35758,0,0,0-.6405-.16266l-2.448220000000001,2.0656099999999995a5.21819,5.21819,0,0,0-1.665,4.144l.0047,3.60767a.49614.49614,0,0,1-.4961999999999982.49687000000000126h-1.0065300000000006a.49621.49621,0,0,1-.49615-.49622v-3.4607799999999997a7.25157,7.25157,0,0,1,2.3398399999999997-5.794459999999999Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout.xml
deleted file mode 100644
index 5504491..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M5.5,10.002a.17879.17879,0,0,0,.27124.18866l1.47589-.67188a.1933.1933,0,0,1,.20471.31177l-2.45184,3.17145l-2.45184-3.1714900000000004a.1933.1933,0,0,1,.20471-.31177l1.476.67188a.17876.17876,0,0,0,.2711299999999994-.18862000000000023v-.002000000000000668a5.51888,5.51888,0,0,1,2.75293-4.76563l.5.86523a4.51856,4.51856,0,0,0-2.25293,3.9003999999999994v.002Zm6.75146-3.89941a4.51948,4.51948,0,0,1,2.24854,3.897409999999999h1a5.5223,5.5223,0,0,0-2.74756-4.7627l-.001440000000000552-.00006000000000039307a.17878.17878,0,0,1-.027789999999999537-.32923999999999953l1.3197899999999994-.9422400000000004a.19332.19332,0,0,0-.16766-.33319l-3.97247.53766l1.52063,3.70911a.19331.19331,0,0,0,.37238-.02142l.1561199999999996-1.6141500000000004a.17945.17945,0,0,1,.29945999999999984-.1412299999999993Zm.4954200000000011,8.663409999999999a.17879.17879,0,0,1,.299.14053l.1561,1.61412a.1933.1933,0,0,0,.37235.02141l1.520669999999999-3.709059999999999l-3.97245-.53766a.1933.1933,0,0,0-.16764.33317l1.31982.94225a.17879.17879,0,0,1-.02781.32923l.00361-.00254a4.57684,4.57684,0,0,1-4.502,0l-.501.86523a5.50442,5.50442,0,0,0,5.50391,0Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_left.xml
deleted file mode 100644
index e3337c5..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M13,6.2a3.8,3.8,0,1,1-3.8000000000000007,3.8a3.80428,3.80428,0,0,1,3.8000000000000007-3.8m0,7a3.2,3.2,0,1,0-3.1999999999999993-3.1999999999999993a3.20363,3.20363,0,0,0,3.1999999999999993,3.1999999999999993m0-7.199999999999999a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm2.82861-5.82813a4.0315,4.0315,0,0,0-.542-.45459a4.078,4.078,0,0,0-5.11475.4541a3.96842,3.96842,0,0,0-1.141099999999998,2.328619999999999h-4.030760000000001a.17879.17879,0,0,1-.18866-.27124l.6718799999999998-1.4758899999999997a.1933.1933,0,0,0-.31177-.20471l-3.17145,2.4518400000000007l3.17145,2.45184a.1933.1933,0,0,0,.31177-.20471l-.6718799999999998-1.4758899999999997a.17879.17879,0,0,1,.1886599999999996-.2712400000000006h5v-.5a2.98063,2.98063,0,0,1,.87891-2.12158a3.06088,3.06088,0,0,1,3.83545-.34082a3.02248,3.02248,0,0,1,.40723.34131a2.99976,2.99976,0,0,1-2.1215899999999994,5.12109h-.5v4h1v-3.030760000000001a4.00038,4.00038,0,0,0,2.3286099999999994-6.797369999999999Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_right.xml
deleted file mode 100644
index c4e3de7..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M7,6.2a3.8,3.8,0,1,1-3.8,3.8a3.80428,3.80428,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.1999999999999993a3.20363,3.20363,0,0,0,3.2,3.1999999999999993m0-7.199999999999999a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm7.83777-5.45184a.1933.1933,0,0,0-.31177.20471l.67188,1.47589a.17881.17881,0,0,1-.18872.2712399999999988h-5.00916v.5a2.99994,2.99994,0,0,1-3,3h-.5v4h1v-3.030760000000001a4.0032,4.0032,0,0,0,3.469239999999999-3.469239999999999h4.03992a.17881.17881,0,0,1,.18872.27124l-.6718799999999998,1.4758899999999997a.1933.1933,0,0,0,.31177.20471l3.1713900000000024-2.4518400000000007Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_sharp_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_sharp_left.xml
deleted file mode 100644
index f6b3999..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_sharp_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M10.994,5.2a3.8,3.8,0,1,1-3.8,3.8a3.80428,3.80428,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.1999999999999993a3.20363,3.20363,0,0,0,3.2,3.2m0-7.2a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm2.8291-5.82813a4.03583,4.03583,0,0,0-.54248-.45459a4.07906,4.07906,0,0,0-5.11475.4541a4.00058,4.00058,0,0,0-.33252,5.28076l-3.0657700000000023,3.06578a.17873.17873,0,0,1-.325-.05847l-.5685799999999994-1.518740000000001a.19332.19332,0,0,0-.36523.07568l-.5087700000000002,3.9762600000000017l3.97626-.50879a.19332.19332,0,0,0,.07568-.36523l-1.5187400000000002-.5685500000000001a.17879.17879,0,0,1-.05835-.3252l-.00037-.00037l3.40378-3.40567l.33838-.353l-.34521-.34619a2.9995,2.9995,0,0,1,.0014699999999994162-4.241229999999998a3.06063,3.06063,0,0,1,3.83545-.34082a3.02673,3.02673,0,0,1,.40771.34131a3,3,0,0,1-2.1220599999999994,5.12109h-.5v4h1v-3.030760000000001a4.00076,4.00076,0,0,0,2.3290900000000008-6.797369999999999Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_sharp_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_sharp_right.xml
deleted file mode 100644
index 820ddf3..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_sharp_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M8.97217,5.2a3.8,3.8,0,1,1-3.8,3.8a3.8043,3.8043,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.2a3.20362,3.20362,0,0,0,3.2,3.2m0-7.2a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm7.491,1.02374a.19328.19328,0,0,0-.36517-.07568l-.5685199999999995,1.5187399999999993a.17883.17883,0,0,1-.32526.05835l-.00018.00018l-3.75726-3.75726l-.35352.35352a2.98022,2.98022,0,0,1-2.121089999999999.8784100000000006h-.5v4h1v-3.030760000000001a3.95621,3.95621,0,0,0,1.95264-.80859l3.07312,3.07275a.17841.17841,0,0,1-.05914.324l-1.5186900000000012.5686000000000018a.1933.1933,0,0,0,.07568.36523l3.9762200000000014.5087699999999984Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_slight_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_slight_left.xml
deleted file mode 100644
index 7891bd7..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_slight_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M10.97473,7.2a3.8,3.8,0,1,1-3.8,3.8a3.80428,3.80428,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.2a3.20363,3.20363,0,0,0,3.2,3.2m0-7.2a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm-5.499-9.20184a.17879.17879,0,0,1,.05835000000000079-.32515999999999945l1.51872-.5685899999999999a.1933.1933,0,0,0-.0757-.36521l-3.97624-.50881l.50881,3.97625a.1933.1933,0,0,0,.36521.0757l.56854-1.51872a.17879.17879,0,0,1,.32521-.05835m6.7061,9.464a4.00038,4.00038,0,0,0,2.32861-6.79736a4.0315,4.0315,0,0,0-.542-.45459a4.07671,4.07671,0,0,0-4.73975.12256l-3.75294-3.749l-.707.708l4.439,4.43311l.353-.35352a3.05971,3.05971,0,0,1,3.83545-.34082a3.02248,3.02248,0,0,1,.40723.34131a2.99976,2.99976,0,0,1-2.1216100000000004,5.121040000000001h-.5v4h1v-3.030760000000001Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_slight_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_slight_right.xml
deleted file mode 100644
index 028dc9f..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_slight_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M8.97128,7.2a3.8,3.8,0,1,1-3.8,3.8a3.80428,3.80428,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.2a3.20363,3.20363,0,0,0,3.2,3.2m0-7.2a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm4.081189999999999-10.548729999999999a.19328.19328,0,0,0-.07568.36517l1.51874.5686a.17878.17878,0,0,1,.05835.3252l.00006.00006l-3.8150899999999996,3.8150899999999988l.35352.35352a2.99976,2.99976,0,0,1-2.1210999999999984,5.121090000000001h-.5v3.97917h1v-3.0099300000000007a4.00123,4.00123,0,0,0,2.66016-6.42236l3.1295699999999993-3.1295399999999978a.17878.17878,0,0,1,.3252.05835l.5684999999999985,1.5187400000000002a.19332.19332,0,0,0,.36523-.07574l.50879-3.9762Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_straight.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_straight.xml
deleted file mode 100644
index 301ce6c..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_ccw_straight.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M10,8.2a3.8,3.8,0,1,1-3.8,3.8000000000000007a3.80427,3.80427,0,0,1,3.8-3.8000000000000007m0,7a3.2,3.2,0,1,0-3.2-3.1999999999999993a3.20363,3.20363,0,0,0,3.2,3.1999999999999993m0-7.199999999999999a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm2.83057-5.82666a3.97135,3.97135,0,0,0-2.33057-1.1425799999999988v-3.0266100000000007a.17881.17881,0,0,1,.27124-.18872l1.4758899999999997.6718700000000002a.19329.19329,0,0,0,.20471-.31177l-2.4518400000000007-3.17138l-2.45184,3.1713899999999997a.1933.1933,0,0,0,.20471.31177l1.476-.67187a.17879.17879,0,0,1,.2711299999999994.18871000000000038v3.99585h.5a3,3,0,1,1,0,6h-.5v3h1v-2.030760000000001a4.00076,4.00076,0,0,0,2.33057-6.7959Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw.xml
deleted file mode 100644
index fe948fc..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <group android:pivotX="10" android:scaleX="-1">
- <path android:fillColor="#FF000000"
- android:pathData="M5.5,10.002a.17879.17879,0,0,0,.27124.18866l1.47589-.67188a.1933.1933,0,0,1,.20471.31177l-2.45184,3.17145l-2.45184-3.1714900000000004a.1933.1933,0,0,1,.20471-.31177l1.476.67188a.17876.17876,0,0,0,.2711299999999994-.18862000000000023v-.002000000000000668a5.51888,5.51888,0,0,1,2.75293-4.76563l.5.86523a4.51856,4.51856,0,0,0-2.25293,3.9003999999999994v.002Zm6.75146-3.89941a4.51948,4.51948,0,0,1,2.24854,3.897409999999999h1a5.5223,5.5223,0,0,0-2.74756-4.7627l-.001440000000000552-.00006000000000039307a.17878.17878,0,0,1-.027789999999999537-.32923999999999953l1.3197899999999994-.9422400000000004a.19332.19332,0,0,0-.16766-.33319l-3.97247.53766l1.52063,3.70911a.19331.19331,0,0,0,.37238-.02142l.1561199999999996-1.6141500000000004a.17945.17945,0,0,1,.29945999999999984-.1412299999999993Zm.4954200000000011,8.663409999999999a.17879.17879,0,0,1,.299.14053l.1561,1.61412a.1933.1933,0,0,0,.37235.02141l1.520669999999999-3.709059999999999l-3.97245-.53766a.1933.1933,0,0,0-.16764.33317l1.31982.94225a.17879.17879,0,0,1-.02781.32923l.00361-.00254a4.57684,4.57684,0,0,1-4.502,0l-.501.86523a5.50442,5.50442,0,0,0,5.50391,0Z"/>
- </group>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_left.xml
deleted file mode 100644
index 038da24..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_left.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <group android:pivotX="10" android:scaleX="-1">
- <path android:fillColor="#FF000000"
- android:pathData="M7,6.2a3.8,3.8,0,1,1-3.8,3.8a3.80428,3.80428,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.1999999999999993a3.20363,3.20363,0,0,0,3.2,3.1999999999999993m0-7.199999999999999a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm7.83777-5.45184a.1933.1933,0,0,0-.31177.20471l.67188,1.47589a.17881.17881,0,0,1-.18872.2712399999999988h-5.00916v.5a2.99994,2.99994,0,0,1-3,3h-.5v4h1v-3.030760000000001a4.0032,4.0032,0,0,0,3.469239999999999-3.469239999999999h4.03992a.17881.17881,0,0,1,.18872.27124l-.6718799999999998,1.4758899999999997a.1933.1933,0,0,0,.31177.20471l3.1713900000000024-2.4518400000000007Z"/>
- </group>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_right.xml
deleted file mode 100644
index a96201d..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_right.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <group android:pivotX="10" android:scaleX="-1">
- <path android:fillColor="#FF000000"
- android:pathData="M13,6.2a3.8,3.8,0,1,1-3.8000000000000007,3.8a3.80428,3.80428,0,0,1,3.8000000000000007-3.8m0,7a3.2,3.2,0,1,0-3.1999999999999993-3.1999999999999993a3.20363,3.20363,0,0,0,3.1999999999999993,3.1999999999999993m0-7.199999999999999a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm2.82861-5.82813a4.0315,4.0315,0,0,0-.542-.45459a4.078,4.078,0,0,0-5.11475.4541a3.96842,3.96842,0,0,0-1.141099999999998,2.328619999999999h-4.030760000000001a.17879.17879,0,0,1-.18866-.27124l.6718799999999998-1.4758899999999997a.1933.1933,0,0,0-.31177-.20471l-3.17145,2.4518400000000007l3.17145,2.45184a.1933.1933,0,0,0,.31177-.20471l-.6718799999999998-1.4758899999999997a.17879.17879,0,0,1,.1886599999999996-.2712400000000006h5v-.5a2.98063,2.98063,0,0,1,.87891-2.12158a3.06088,3.06088,0,0,1,3.83545-.34082a3.02248,3.02248,0,0,1,.40723.34131a2.99976,2.99976,0,0,1-2.1215899999999994,5.12109h-.5v4h1v-3.030760000000001a4.00038,4.00038,0,0,0,2.3286099999999994-6.797369999999999Z"/>
- </group>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_sharp_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_sharp_left.xml
deleted file mode 100644
index da060af..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_sharp_left.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <group android:pivotX="10" android:scaleX="-1">
- <path android:fillColor="#FF000000"
- android:pathData="M8.97217,5.2a3.8,3.8,0,1,1-3.8,3.8a3.8043,3.8043,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.2a3.20362,3.20362,0,0,0,3.2,3.2m0-7.2a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm7.491,1.02374a.19328.19328,0,0,0-.36517-.07568l-.5685199999999995,1.5187399999999993a.17883.17883,0,0,1-.32526.05835l-.00018.00018l-3.75726-3.75726l-.35352.35352a2.98022,2.98022,0,0,1-2.121089999999999.8784100000000006h-.5v4h1v-3.030760000000001a3.95621,3.95621,0,0,0,1.95264-.80859l3.07312,3.07275a.17841.17841,0,0,1-.05914.324l-1.5186900000000012.5686000000000018a.1933.1933,0,0,0,.07568.36523l3.9762200000000014.5087699999999984Z"/>
- </group>
-</vector>
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_sharp_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_sharp_right.xml
deleted file mode 100644
index 91165f8..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_sharp_right.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <group android:pivotX="10" android:scaleX="-1">
- <path android:fillColor="#FF000000"
- android:pathData="M10.994,5.2a3.8,3.8,0,1,1-3.8,3.8a3.80428,3.80428,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.1999999999999993a3.20363,3.20363,0,0,0,3.2,3.2m0-7.2a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm2.8291-5.82813a4.03583,4.03583,0,0,0-.54248-.45459a4.07906,4.07906,0,0,0-5.11475.4541a4.00058,4.00058,0,0,0-.33252,5.28076l-3.0657700000000023,3.06578a.17873.17873,0,0,1-.325-.05847l-.5685799999999994-1.518740000000001a.19332.19332,0,0,0-.36523.07568l-.5087700000000002,3.9762600000000017l3.97626-.50879a.19332.19332,0,0,0,.07568-.36523l-1.5187400000000002-.5685500000000001a.17879.17879,0,0,1-.05835-.3252l-.00037-.00037l3.40378-3.40567l.33838-.353l-.34521-.34619a2.9995,2.9995,0,0,1,.0014699999999994162-4.241229999999998a3.06063,3.06063,0,0,1,3.83545-.34082a3.02673,3.02673,0,0,1,.40771.34131a3,3,0,0,1-2.1220599999999994,5.12109h-.5v4h1v-3.030760000000001a4.00076,4.00076,0,0,0,2.3290900000000008-6.797369999999999Z"/>
- </group>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_slight_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_slight_left.xml
deleted file mode 100644
index 6bdd564..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_slight_left.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <group android:pivotX="10" android:scaleX="-1">
- <path android:fillColor="#FF000000"
- android:pathData="M8.97128,7.2a3.8,3.8,0,1,1-3.8,3.8a3.80428,3.80428,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.2a3.20363,3.20363,0,0,0,3.2,3.2m0-7.2a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm4.081189999999999-10.548729999999999a.19328.19328,0,0,0-.07568.36517l1.51874.5686a.17878.17878,0,0,1,.05835.3252l.00006.00006l-3.8150899999999996,3.8150899999999988l.35352.35352a2.99976,2.99976,0,0,1-2.1210999999999984,5.121090000000001h-.5v3.97917h1v-3.0099300000000007a4.00123,4.00123,0,0,0,2.66016-6.42236l3.1295699999999993-3.1295399999999978a.17878.17878,0,0,1,.3252.05835l.5684999999999985,1.5187400000000002a.19332.19332,0,0,0,.36523-.07574l.50879-3.9762Z"/>
- </group>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_slight_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_slight_right.xml
deleted file mode 100644
index 00c0fa5..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_slight_right.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <group android:pivotX="10" android:scaleX="-1">
- <path android:fillColor="#FF000000"
- android:pathData="M10.97473,7.2a3.8,3.8,0,1,1-3.8,3.8a3.80428,3.80428,0,0,1,3.8-3.8m0,7a3.2,3.2,0,1,0-3.2-3.2a3.20363,3.20363,0,0,0,3.2,3.2m0-7.2a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm-5.499-9.20184a.17879.17879,0,0,1,.05835000000000079-.32515999999999945l1.51872-.5685899999999999a.1933.1933,0,0,0-.0757-.36521l-3.97624-.50881l.50881,3.97625a.1933.1933,0,0,0,.36521.0757l.56854-1.51872a.17879.17879,0,0,1,.32521-.05835m6.7061,9.464a4.00038,4.00038,0,0,0,2.32861-6.79736a4.0315,4.0315,0,0,0-.542-.45459a4.07671,4.07671,0,0,0-4.73975.12256l-3.75294-3.749l-.707.708l4.439,4.43311l.353-.35352a3.05971,3.05971,0,0,1,3.83545-.34082a3.02248,3.02248,0,0,1,.40723.34131a2.99976,2.99976,0,0,1-2.1216100000000004,5.121040000000001h-.5v4h1v-3.030760000000001Z"/>
- </group>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_straight.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_straight.xml
deleted file mode 100644
index 0961145..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_roundabout_cw_straight.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <group android:pivotX="10" android:scaleX="-1">
- <path android:fillColor="#FF000000"
- android:pathData="M10,8.2a3.8,3.8,0,1,1-3.8,3.8000000000000007a3.80427,3.80427,0,0,1,3.8-3.8000000000000007m0,7a3.2,3.2,0,1,0-3.2-3.1999999999999993a3.20363,3.20363,0,0,0,3.2,3.1999999999999993m0-7.199999999999999a4,4,0,1,0,4,4a4.00458,4.00458,0,0,0-4-4h0Zm0,7a3,3,0,1,1,3-3a3.00328,3.00328,0,0,1-3,3h0Zm2.83057-5.82666a3.97135,3.97135,0,0,0-2.33057-1.1425799999999988v-3.0266100000000007a.17881.17881,0,0,1,.27124-.18872l1.4758899999999997.6718700000000002a.19329.19329,0,0,0,.20471-.31177l-2.4518400000000007-3.17138l-2.45184,3.1713899999999997a.1933.1933,0,0,0,.20471.31177l1.476-.67187a.17879.17879,0,0,1,.2711299999999994.18871000000000038v3.99585h.5a3,3,0,1,1,0,6h-.5v3h1v-2.030760000000001a4.00076,4.00076,0,0,0,2.33057-6.7959Z"/>
- </group>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_turn_left.xml
deleted file mode 100644
index faa7027..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M10,5.97986l.011.00183a6.06019,6.06019,0,0,1,5.989000000000001,6.07324v3.9450699999999994h-.003109999999999502l.002,1.50317a.49614.49614,0,0,1-.49620000000000175.4968299999999992h-1.0064700000000002a.49622.49622,0,0,1-.4962199999999992-.496220000000001v-5.448849999999998a4.05782,4.05782,0,0,0-3.98877-4.07324h-1.99878a.3576.3576,0,0,0-.37738.54248l1.3437500000000009,2.951830000000001a.38659.38659,0,0,1-.62354.40942l-6.34698-4.885420000000002l6.347-4.922a.38659.38659,0,0,1,.62354.40942l-1.3437700000000001,2.9518499999999994a.35757.35757,0,0,0,.37738.54242h1.9875500000000006"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_turn_right.xml
deleted file mode 100644
index 6ef4749..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M9.98877,7.98169a4.05782,4.05782,0,0,0-3.9887700000000006,4.07324v5.44885a.49622.49622,0,0,1-.4962200000000001.496220000000001h-1.0064700000000002a.49614.49614,0,0,1-.49615-.49683l.0019500000000007844-1.5031700000000008h-.0031100000000003902v-3.9450699999999994a6.06019,6.06019,0,0,1,5.989000000000001-6.07324l.010999999999999233-.0018299999999999983v.0018299999999999983h1.98755a.35757.35757,0,0,0,.37738-.54242l-1.3437500000000018-2.9518400000000007a.38659.38659,0,0,1,.6235300000000006-.40942999999999996l6.346990000000002,4.922000000000001l-6.347,4.88544a.38659.38659,0,0,1-.62354-.40942l1.34375-2.95184a.3576.3576,0,0,0-.37738-.54248h-1.998759999999999Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_sharp_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_turn_sharp_left.xml
deleted file mode 100644
index 9024be2..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_sharp_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M15.49771,17.99542a.49779.49779,0,0,1-.49779-.49779v-12.4983l-.2797799999999988-.006330000000000169a2.56758,2.56758,0,0,0-2.0957.79l-5.39527,4.61283a.34918.34918,0,0,0,.08252.63177l2.92877,1.39331a.38658.38658,0,0,1-.21344.71472l-8.0105.33209l1.69568-7.836a.38661.38661,0,0,1,.74072-.0882l.8725,3.12372a.35757.35757,0,0,0,.638.17206l.0037800000000007827.00446999999999953l5.392099999999999-4.609089999999999a4.46634,4.46634,0,0,1,3.38477-1.24121l.26416.002a1.92935,1.92935,0,0,1,1.43408.56885a2.10247,2.10247,0,0,1,.55713,1.46045l.000460000000000349,12.472840000000001a.49779.49779,0,0,1-.49779.49781h-1.0044Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_sharp_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_turn_sharp_right.xml
deleted file mode 100644
index 3394364..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_sharp_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M3.49789,17.99542a.49779.49779,0,0,1-.49779-.49781l.00047000000000041453-12.472889999999998a2.10247,2.10247,0,0,1,.5571299999999999-1.4604500000000002a1.92935,1.92935,0,0,1,1.43408-.56885l.26416-.002a4.46634,4.46634,0,0,1,3.38476,1.2412599999999996l5.392099999999999,4.609089999999999l.00378-.00446a.35757.35757,0,0,0,.638-.17206l.8725-3.12372a.38661.38661,0,0,1,.74072.0882l1.69568,7.836l-8.01048-.3320899999999991a.38658.38658,0,0,1-.21344-.71472l2.92877-1.39331a.34918.34918,0,0,0,.08252-.63177l-5.395280000000001-4.612840000000001a2.56758,2.56758,0,0,0-2.0957-.79l-.27979.00635v12.4983a.49779.49779,0,0,1-.49779.49779h-1.0043999999999995Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_slight_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_turn_slight_left.xml
deleted file mode 100644
index 431736f..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_slight_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M14.9859,14.043v3.46082a.49621.49621,0,0,1-.4961600000000015.4961800000000025h-1.0065299999999997a.49614.49614,0,0,1-.49615-.49683l.0047-3.60767a5.21819,5.21819,0,0,0-1.665-4.144l-2.448220000000001-2.0656499999999998a.35758.35758,0,0,0-.6405.16266l-.91821,3.1106a.38663.38663,0,0,1-.7393899999999993-.09910999999999959l-1.5804400000000003-7.859999999999999l8.00476.44965a.38658.38658,0,0,1,.20294.71777l-2.9489199999999993,1.3501599999999998a.3576.3576,0,0,0-.07019.6571l2.45746,2.07385a7.25158,7.25158,0,0,1,2.339850000000002,5.7944700000000005Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_slight_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_turn_slight_right.xml
deleted file mode 100644
index 0ab8aef..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_turn_slight_right.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M7.35395,8.24854l2.45746-2.07386a.3576.3576,0,0,0-.07019-.6571l-2.94892-1.3501600000000007a.38658.38658,0,0,1,.20294-.71777l8.004760000000001-.4496500000000001l-1.58044,7.86a.38663.38663,0,0,1-.73938.09912l-.9181799999999996-3.1106099999999985a.35758.35758,0,0,0-.6405-.16266l-2.448220000000001,2.0656099999999995a5.21819,5.21819,0,0,0-1.665,4.144l.0047,3.60767a.49614.49614,0,0,1-.49618999999999946.49687000000000126h-1.0065300000000006a.49621.49621,0,0,1-.49615-.49622v-3.4607799999999997a7.25157,7.25157,0,0,1,2.3398400000000006-5.794459999999999Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_uturn_left.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_uturn_left.xml
deleted file mode 100644
index bfb9e0c..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_uturn_left.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
- <path android:fillColor="#FF000000"
- android:pathData="M17,8v9.49652a.50346.50346,0,0,1-.5034799999999997.5034799999999997h-.993a.50346.50346,0,0,1-.50352-.5034799999999997v-9.49652a3.5,3.5,0,0,0-7,0v4h-.009089999999999598a.35757.35757,0,0,0,.54242.37738l2.95184-1.34375a.3866.3866,0,0,1,.40942.62354l-4.9036800000000005,6.342829999999999l-4.9037500000000005-6.342829999999999a.3866.3866,0,0,1,.40942-.62354l2.95184,1.34375a.3576.3576,0,0,0,.5424900000000008-.3773800000000005h.009089999999999598v-4a5.5,5.5,0,0,1,11,0Z"/>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/direction_uturn_right.xml b/tests/DirectRenderingClusterSample/res/drawable/direction_uturn_right.xml
deleted file mode 100644
index 8fc9223..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/direction_uturn_right.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp"
- android:height="20dp" android:viewportWidth="20" android:viewportHeight="20"
- android:pivotX="10" android:scaleX="-1">
- <group android:pivotX="10" android:scaleX="-1">
- <path android:fillColor="#FF000000"
- android:pathData="M17,8v9.49652a.50346.50346,0,0,1-.5034799999999997.5034799999999997h-.993a.50346.50346,0,0,1-.50352-.5034799999999997v-9.49652a3.5,3.5,0,0,0-7,0v4h-.009089999999999598a.35757.35757,0,0,0,.54242.37738l2.95184-1.34375a.3866.3866,0,0,1,.40942.62354l-4.9036800000000005,6.342829999999999l-4.9037500000000005-6.342829999999999a.3866.3866,0,0,1,.40942-.62354l2.95184,1.34375a.3576.3576,0,0,0,.5424900000000008-.3773800000000005h.009089999999999598v-4a5.5,5.5,0,0,1,11,0Z"/>
- </group>
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/focused_button_shape.xml b/tests/DirectRenderingClusterSample/res/drawable/focused_button_shape.xml
deleted file mode 100644
index 9ded30c..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/focused_button_shape.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <stroke
- android:width="2dp"
- android:color="#333333"/>
- <corners
- android:radius="7dp"/>
- <padding
- android:left="5dp"
- android:top="5dp"
- android:right="5dp"
- android:bottom="5dp"/>
-</shape>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/gradient_bottom.xml b/tests/DirectRenderingClusterSample/res/drawable/gradient_bottom.xml
deleted file mode 100644
index 8006864..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/gradient_bottom.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <gradient
- android:startColor="#00000000"
- android:endColor="#FF000000"
- android:angle="270"
- android:dither="true"
- />
-</shape>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/gradient_top.xml b/tests/DirectRenderingClusterSample/res/drawable/gradient_top.xml
deleted file mode 100644
index 74932ad..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/gradient_top.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <gradient
- android:startColor="#00000000"
- android:endColor="#FF000000"
- android:angle="90"
- android:dither="true"
- />
-</shape>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/seekbar_background.xml b/tests/DirectRenderingClusterSample/res/drawable/seekbar_background.xml
deleted file mode 100644
index ec08455..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/seekbar_background.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:id="@android:id/background">
- <shape android:shape="line">
- <stroke android:width="@dimen/playback_seekbar_track_height"/>
- </shape>
- </item>
-
- <item android:id="@android:id/progress">
- <clip>
- <shape android:shape="line">
- <stroke android:width="@dimen/playback_seekbar_track_height"/>
- </shape>
- </clip>
- </item>
-
-</layer-list>
diff --git a/tests/DirectRenderingClusterSample/res/drawable/seekbar_thumb.xml b/tests/DirectRenderingClusterSample/res/drawable/seekbar_thumb.xml
deleted file mode 100644
index 1d0b4a1..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/seekbar_thumb.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <solid android:color="@color/progress_bar_thumb_color"/>
- <size
- android:width="@dimen/playback_seekbar_thumb_width"
- android:height="@dimen/playback_seekbar_thumb_height"/>
-</shape>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/drawable/speedometer.xml b/tests/DirectRenderingClusterSample/res/drawable/speedometer.xml
deleted file mode 100644
index d97c54e..0000000
--- a/tests/DirectRenderingClusterSample/res/drawable/speedometer.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:aapt="http://schemas.android.com/aapt"
- android:width="200dp"
- android:height="200dp"
- android:viewportHeight="64"
- android:viewportWidth="64">
-
- <path
- android:pathData="M0,32
- A32,32 0 1,1 64,32
- A32,32 0 1,1 0,32 Z">
- <aapt:attr name="android:fillColor">
- <gradient
- android:centerX="32"
- android:centerY="32"
- android:gradientRadius="32"
- android:type="radial">
- <item
- android:color="#FF000000"
- android:offset="0.0"/>
- <item
- android:color="#FF000000"
- android:offset="0.94"/>
- <item
- android:color="#00000000"
- android:offset="1.0"/>
- </gradient>
- </aapt:attr>
- </path>
-
- <path
- android:fillColor="#000"
- android:strokeWidth="0.25"
- android:pathData="M2,32
- A30,30 0 1,1 62,32
- A30,30 0 1,1 2,32 Z">
- <aapt:attr name="android:strokeColor">
- <gradient
- android:startX="0"
- android:startY="10"
- android:startColor="#000"
- android:endX="0"
- android:endY="150"
- android:endColor="#000"
- android:centerColor="#DDD"
- android:type="linear"/>
- </aapt:attr>
- </path>
-
-</vector>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/layout/activity_main.xml b/tests/DirectRenderingClusterSample/res/layout/activity_main.xml
deleted file mode 100644
index fa8db14..0000000
--- a/tests/DirectRenderingClusterSample/res/layout/activity_main.xml
+++ /dev/null
@@ -1,237 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/activity_main"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_dark"
- android:windowIsFloating="true"
- tools:context=".MainClusterActivity">
-
- <androidx.constraintlayout.widget.Guideline
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/left_unobscured"
- android:orientation="vertical"
- app:layout_constraintGuide_begin="@dimen/speedometer_overlap_width"/>
-
- <androidx.constraintlayout.widget.Guideline
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/right_unobscured"
- android:orientation="vertical"
- app:layout_constraintGuide_end="@dimen/speedometer_overlap_width"/>
-
- <androidx.constraintlayout.widget.Guideline
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/gauges_top"
- android:orientation="horizontal"
- app:layout_constraintGuide_begin="@dimen/speedometer_top"/>
-
- <androidx.viewpager.widget.ViewPager
- android:id="@+id/pager"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@+id/info"/>
-
- <LinearLayout
- android:id="@+id/info"
- android:layout_width="0dp"
- android:layout_height="@dimen/info_height"
- app:layout_constraintLeft_toRightOf="@+id/left_unobscured"
- app:layout_constraintRight_toLeftOf="@+id/right_unobscured"
- app:layout_constraintBottom_toBottomOf="parent"
- android:gravity="center">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="start">
-
- <TextView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:includeFontPadding="false"
- android:text="@string/info_fuel_label"
- android:textSize="@dimen/info_label_text_size"/>
-
- <TextView
- android:id="@+id/info_fuel"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:includeFontPadding="false"
- android:text="@string/info_value_empty"
- android:textSize="@dimen/info_value_text_size"/>
-
- <TextView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:includeFontPadding="false"
- android:text="@string/info_range_label"
- android:textSize="@dimen/info_label_text_size"/>
-
- <TextView
- android:id="@+id/info_range"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:includeFontPadding="false"
- android:text="@string/info_value_empty"
- android:textSize="@dimen/info_value_text_size"/>
- </LinearLayout>
-
- <include
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:id="@+id/navigation_state"
- layout="@layout/include_navigation_state"/>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="end">
-
- <TextView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:includeFontPadding="false"
- android:text="@string/info_speed_label"
- android:textSize="@dimen/info_label_text_size"/>
-
- <TextView
- android:id="@+id/info_speed"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:includeFontPadding="false"
- android:text="@string/info_value_empty"
- android:textSize="@dimen/info_value_text_size"/>
-
- <TextView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:includeFontPadding="false"
- android:text="@string/info_rpm_label"
- android:textSize="@dimen/info_label_text_size"/>
-
- <TextView
- android:id="@+id/info_rpm"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:includeFontPadding="false"
- android:text="@string/info_value_empty"
- android:textSize="@dimen/info_value_text_size"/>
- </LinearLayout>
- </LinearLayout>
-
- <ImageView
- android:id="@+id/left_gauge"
- android:layout_width="@dimen/speedometer_width"
- android:layout_height="@dimen/speedometer_height"
- android:src="@drawable/speedometer"
- android:elevation="2dp"
- app:layout_constraintTop_toBottomOf="@+id/gauges_top"
- app:layout_constraintRight_toLeftOf="@+id/left_unobscured"/>
-
- <ImageView
- android:id="@+id/right_gauge"
- android:layout_width="@dimen/speedometer_width"
- android:layout_height="@dimen/speedometer_height"
- android:src="@drawable/speedometer"
- android:elevation="2dp"
- app:layout_constraintTop_toBottomOf="@+id/gauges_top"
- app:layout_constraintLeft_toRightOf="@+id/right_unobscured"/>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:translationZ="4dp"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintBottom_toBottomOf="parent">
-
- <Button
- android:id="@+id/btn_nav"
- android:layout_width="@dimen/facet_icon_size"
- android:layout_height="@dimen/facet_icon_size"
- android:layout_margin="@dimen/facet_icon_margin"
- android:background="@drawable/ic_nav"
- android:backgroundTint="@color/icon_color"
- android:focusableInTouchMode="true" />
- <Button
- android:id="@+id/btn_phone"
- android:layout_width="@dimen/facet_icon_size"
- android:layout_height="@dimen/facet_icon_size"
- android:layout_margin="@dimen/facet_icon_margin"
- android:background="@drawable/ic_phone"
- android:backgroundTint="@color/icon_color"
- android:focusableInTouchMode="true" />
- <Button
- android:id="@+id/btn_music"
- android:layout_width="@dimen/facet_icon_size"
- android:layout_height="@dimen/facet_icon_size"
- android:layout_margin="@dimen/facet_icon_margin"
- android:background="@drawable/ic_music"
- android:backgroundTint="@color/icon_color"
- android:focusableInTouchMode="true" />
- <Button
- android:id="@+id/btn_car_info"
- android:layout_width="@dimen/facet_icon_size"
- android:layout_height="@dimen/facet_icon_size"
- android:layout_margin="@dimen/facet_icon_margin"
- android:background="@drawable/ic_car_info"
- android:backgroundTint="@color/icon_color"
- android:focusableInTouchMode="true" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:translationZ="4dp"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintBottom_toBottomOf="parent">
-
- <TextView
- android:id="@+id/gear_parked"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginHorizontal="@dimen/gear_icon_margin"
- android:text="@string/gear_parked"
- android:textColor="@color/icon_color"
- android:textSize="@dimen/gear_text_size"/>
-
- <TextView
- android:id="@+id/gear_reverse"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginHorizontal="@dimen/gear_icon_margin"
- android:text="@string/gear_reverse"
- android:textColor="@color/icon_color"
- android:textSize="@dimen/gear_text_size"/>
-
- <TextView
- android:id="@+id/gear_neutral"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginHorizontal="@dimen/gear_icon_margin"
- android:text="@string/gear_neutral"
- android:textColor="@color/icon_color"
- android:textSize="@dimen/gear_text_size"/>
-
- <TextView
- android:id="@+id/gear_drive"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginHorizontal="@dimen/gear_icon_margin"
- android:text="@string/gear_drive"
- android:textColor="@color/icon_color"
- android:textSize="@dimen/gear_text_size"/>
-
- </LinearLayout>
-</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/tests/DirectRenderingClusterSample/res/layout/fragment_car_info.xml b/tests/DirectRenderingClusterSample/res/layout/fragment_car_info.xml
deleted file mode 100644
index 3a1f5ab..0000000
--- a/tests/DirectRenderingClusterSample/res/layout/fragment_car_info.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="com.google.experiments.client.pavelm.fakeclusterux.CarInfoFragment">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="32 psi"
- android:layout_gravity="center_horizontal"
- android:layout_marginLeft="-80dp"
- />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="33 psi"
- android:layout_gravity="center_horizontal"
- android:layout_marginLeft="80dp"
- />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="33 psi"
- android:layout_gravity="center_horizontal|bottom"
- android:layout_marginLeft="80dp"
- />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="31 psi"
- android:layout_gravity="center_horizontal|bottom"
- android:layout_marginLeft="-80dp"
- />
-
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:src="@drawable/car_top_view"
- android:padding="30dp"
- android:scaleType="fitCenter" />
-
-</FrameLayout>
diff --git a/tests/DirectRenderingClusterSample/res/layout/fragment_music.xml b/tests/DirectRenderingClusterSample/res/layout/fragment_music.xml
deleted file mode 100644
index f9c72f7..0000000
--- a/tests/DirectRenderingClusterSample/res/layout/fragment_music.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-<androidx.cardview.widget.CardView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- app:cardElevation="0dp"
- app:cardCornerRadius="6dp">
-
- <com.android.car.apps.common.CrossfadeImageView
- android:id="@+id/album_background"
- android:foreground="?android:attr/selectableItemBackground"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="fitStart" />
-
- <View
- android:id="@+id/playback_scrim"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/album_art_scrim"
- android:alpha="@dimen/album_art_scrim_alpha"/>
-
- <androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/playback_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/app_name"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/playback_fragment_text_margin_top"
- android:layout_marginLeft="@dimen/playback_fragment_text_margin_x"
- android:layout_marginRight="@dimen/playback_fragment_text_margin_x"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:ellipsize="end"
- android:maxLines="1"
- android:includeFontPadding="false"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="parent"/>
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/margin_start"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:orientation="vertical"
- app:layout_constraintGuide_begin="@dimen/fragment_playback_guide_margin_x"/>
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/margin_end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- app:layout_constraintGuide_end="@dimen/fragment_playback_guide_margin_x"/>
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/margin_top"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- app:layout_constraintGuide_begin="@dimen/fragment_playback_guide_margin_top"/>
-
- <ImageView
- android:id="@+id/album_art"
- android:layout_width="@dimen/playback_album_art_size_normal"
- android:layout_height="@dimen/playback_album_art_size_normal"
- android:layout_marginStart="@dimen/fragment_metadata_art_margin_start"
- android:layout_marginEnd="@dimen/fragment_metadata_art_margin_end"
- android:contentDescription="@string/album_art"
- android:background="@color/album_art_background"
- android:scaleType="centerCrop"
- android:transitionName="@string/album_art"
- app:layout_constraintTop_toTopOf="@+id/app_name"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="@+id/margin_start"
- tools:src="@drawable/ic_person"/>
-
- <include
- android:id="@+id/metadata_subcontainer"
- layout="@layout/metadata_normal"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/fragment_metadata_metadata_margin_start"
- android:layout_marginEnd="@dimen/fragment_metadata_metadata_margin_end"
- app:layout_constraintBottom_toBottomOf="@+id/album_art"
- app:layout_constraintEnd_toEndOf="@+id/margin_end"
- app:layout_constraintStart_toEndOf="@+id/album_art"
- app:layout_constraintTop_toTopOf="@+id/album_art"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
-</androidx.cardview.widget.CardView>
diff --git a/tests/DirectRenderingClusterSample/res/layout/fragment_navigation.xml b/tests/DirectRenderingClusterSample/res/layout/fragment_navigation.xml
deleted file mode 100644
index 54894c2..0000000
--- a/tests/DirectRenderingClusterSample/res/layout/fragment_navigation.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".NavigationFragment">
-
- <SurfaceView
- android:id="@+id/nav_surface"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-
- <ProgressBar
- android:id="@+id/progress_bar"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@+id/message"/>
-
- <TextView
- android:id="@+id/message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/select_nav_app"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/progress_bar"/>
-
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="@dimen/navigation_gradient_height"
- android:src="@drawable/gradient_top"
- app:layout_constraintTop_toTopOf="parent"/>
-
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="@dimen/navigation_gradient_height"
- android:src="@drawable/gradient_bottom"
- app:layout_constraintBottom_toBottomOf="parent"/>
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/layout/fragment_phone.xml b/tests/DirectRenderingClusterSample/res/layout/fragment_phone.xml
deleted file mode 100644
index b7f903b..0000000
--- a/tests/DirectRenderingClusterSample/res/layout/fragment_phone.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <FrameLayout
- android:id="@+id/user_profile_container"
- android:layout_width="match_parent"
- android:gravity="center"
- android:layout_height="0dp"
- android:layout_weight="1">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="vertical">
- <ImageView
- android:id="@+id/avatar"
- android:layout_width="@dimen/large_avatar_icon_size"
- android:layout_height="@dimen/large_avatar_icon_size"
- android:layout_gravity="center"
- android:scaleType="fitCenter" />
- <TextView
- android:id="@+id/title"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/user_profile_title_padding_top"
- android:focusable="true"
- android:maxLines="1"
- android:gravity="center"/>
- <TextView
- android:id="@+id/body"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/user_profile_body_padding_top"
- android:gravity="center"
- android:maxLines="1"/>
- </LinearLayout>
-
- </FrameLayout>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/layout/include_navigation_state.xml b/tests/DirectRenderingClusterSample/res/layout/include_navigation_state.xml
deleted file mode 100644
index 8f1196a..0000000
--- a/tests/DirectRenderingClusterSample/res/layout/include_navigation_state.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <ImageView
- android:id="@+id/maneuver"
- android:layout_width="@dimen/maneuver_width"
- android:layout_height="@dimen/maneuver_height"
- android:layout_marginLeft="@dimen/maneuver_margin"
- android:layout_marginRight="@dimen/maneuver_margin"
- android:tint="@android:color/white"/>
- <ImageView
- android:id="@+id/provided_maneuver"
- android:layout_width="@dimen/provided_maneuver_width"
- android:layout_height="@dimen/provided_maneuver_height"
- android:layout_gravity="center"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_weight="1.0">
-
- <TextView
- android:id="@+id/distance"
- android:layout_width="@dimen/distance_width"
- android:layout_height="wrap_content"
- android:maxLines="1"
- android:textSize="@dimen/distance_text_size"/>
-
- <android.car.cluster.sample.LaneView
- android:id="@+id/lane"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/laneview_height"
- android:layout_alignParentRight="true"/>
- </LinearLayout>
-
- <android.car.cluster.sample.CueView
- android:id="@+id/cue"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="1"
- android:textSize="@dimen/cue_text_size"/>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <TextView
- android:id="@+id/eta"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_marginRight="@dimen/eta_margin_right"
- android:maxLines="1"
- android:textSize="@dimen/eta_text_size"/>
-
- <TextView
- android:id="@+id/segment"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:maxLines="1"
- android:ellipsize="end"
- android:textSize="@dimen/segment_text_size"/>
- </LinearLayout>
-
- <android.car.cluster.sample.LaneView
- android:id="@+id/provided_lane"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/provided_laneview_height"
- android:layout_marginLeft="@dimen/distance_width"/>
- </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/layout/metadata_normal.xml b/tests/DirectRenderingClusterSample/res/layout/metadata_normal.xml
deleted file mode 100644
index 5cb75a6..0000000
--- a/tests/DirectRenderingClusterSample/res/layout/metadata_normal.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/metadata_subcontainer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:focusable="false">
-
- <TextView
- android:id="@+id/title"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:includeFontPadding="false"
- android:maxLines="@integer/playback_title_text_max_lines"
- android:textAppearance="?android:attr/textAppearanceLarge"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="Body 1 Header"/>
- <TextView
- android:id="@+id/subtitle"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/metadata_normal_subtitle_margin_top"
- android:layout_marginEnd="@dimen/metadata_normal_subtitle_margin_end"
- android:ellipsize="end"
- android:maxLines="@integer/playback_subtitle_text_max_lines"
- android:textAppearance="?android:attr/textAppearanceMedium"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/time"
- app:layout_constraintTop_toBottomOf="@+id/title"
- tools:text="Body 2"/>
- <TextView
- android:id="@+id/time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/metadata_normal_time_margin_top"
- android:ellipsize="end"
- android:maxLines="@integer/playback_subtitle_text_max_lines"
- android:gravity="end"
- android:textAppearance="?android:attr/textAppearanceMedium"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/title"
- tools:text="3:27 / 4:03"/>
- <SeekBar
- android:id="@+id/seek_bar"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/metadata_normal_seek_margin_top"
- android:clickable="false"
- android:focusable="false"
- android:paddingEnd="@dimen/playback_seekbar_padding_end"
- android:paddingStart="@dimen/playback_seekbar_padding_start"
- android:progressDrawable="@drawable/seekbar_background"
- android:thumb="@drawable/seekbar_thumb"
- android:splitTrack="false"
- android:progressTint="@color/progress_bar_highlight"
- android:progressBackgroundTint="@color/progress_bar_background"
- android:background="@null"
- android:visibility="invisible"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/subtitle"
- tools:progress="70"
- tools:visibility="visible"/>
-
-</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/tests/DirectRenderingClusterSample/res/mipmap-hdpi/ic_launcher.png b/tests/DirectRenderingClusterSample/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bc..0000000
--- a/tests/DirectRenderingClusterSample/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/mipmap-mdpi/ic_launcher.png b/tests/DirectRenderingClusterSample/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0c..0000000
--- a/tests/DirectRenderingClusterSample/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/mipmap-xhdpi/ic_launcher.png b/tests/DirectRenderingClusterSample/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0..0000000
--- a/tests/DirectRenderingClusterSample/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/mipmap-xxhdpi/ic_launcher.png b/tests/DirectRenderingClusterSample/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72c..0000000
--- a/tests/DirectRenderingClusterSample/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/mipmap-xxxhdpi/ic_launcher.png b/tests/DirectRenderingClusterSample/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e1..0000000
--- a/tests/DirectRenderingClusterSample/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/DirectRenderingClusterSample/res/values-en-rUS/dimens.xml b/tests/DirectRenderingClusterSample/res/values-en-rUS/dimens.xml
deleted file mode 100644
index 05eef22..0000000
--- a/tests/DirectRenderingClusterSample/res/values-en-rUS/dimens.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- -->
- <!-- Sensor value conversion constants -->
- <!-- -->
- <!-- Speed: meters per second to miles per hour -->
- <item name="speed_factor" format="float" type="dimen">2.236936</item>
- <!-- Distance: miles to meters -->
- <item name="distance_factor" format="float" type="dimen">1609.344</item>
-</resources>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/res/values-w820dp/dimens.xml b/tests/DirectRenderingClusterSample/res/values-w820dp/dimens.xml
deleted file mode 100644
index 63fc816..0000000
--- a/tests/DirectRenderingClusterSample/res/values-w820dp/dimens.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<resources>
- <!-- Example customization of dimensions originally defined in res/values/dimens.xml
- (such as screen margins) for screens with more than 820dp of available width. This
- would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
- <dimen name="activity_horizontal_margin">64dp</dimen>
-</resources>
diff --git a/tests/DirectRenderingClusterSample/res/values/colors.xml b/tests/DirectRenderingClusterSample/res/values/colors.xml
deleted file mode 100644
index c40f199..0000000
--- a/tests/DirectRenderingClusterSample/res/values/colors.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <color name="colorPrimary">#3F51B5</color>
- <color name="colorPrimaryDark">#303F9F</color>
- <color name="colorAccent">#FF4081</color>
- <color name="darkBlue">#2b2b77</color>
-
- <!-- Gear and facet icon colors -->
- <color name="icon_selected">#6EDDFF</color>
- <color name="icon_unselected">#1B378A</color>
-
- <!-- LaneView highlight colors -->
- <color name="laneDirection">#888888</color>
- <color name="laneDirectionHighlighted">#FFFFFF</color>
-
- <!-- Traffic colors -->
- <color name="low_traffic">#0F9D58</color>
- <color name="medium_traffic">#F2B300</color>
- <color name="high_traffic">#E06055</color>
- <color name="unknown_traffic">#4285F4</color>
-
- <color name="album_art_background">@*android:color/car_grey_100</color>
- <!-- Color used on the placeholder album art -->
- <color name="album_art_placeholder_color">@*android:color/car_grey_800</color>
- <!-- Color used on the progress bar background -->
- <color name="progress_bar_background">@*android:color/car_seekbar_track_background</color>
- <!-- Color used on the progress bar -->
- <color name="progress_bar_highlight">@*android:color/car_accent</color>
- <!-- Color used on the thumb of the progress bar -->
- <color name="progress_bar_thumb_color">@*android:color/car_accent</color>
-</resources>
diff --git a/tests/DirectRenderingClusterSample/res/values/dimens.xml b/tests/DirectRenderingClusterSample/res/values/dimens.xml
deleted file mode 100644
index 21aec67..0000000
--- a/tests/DirectRenderingClusterSample/res/values/dimens.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<resources>
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
- <!-- Size and position of speedometers -->
- <dimen name="speedometer_height">600dp</dimen>
- <dimen name="speedometer_width">600dp</dimen>
- <dimen name="speedometer_overlap_width">90dp</dimen>
- <dimen name="speedometer_top">20dp</dimen>
- <!-- Navigation fragment gradients -->
- <dimen name="navigation_gradient_height">15dp</dimen>
- <!-- Facet buttons -->
- <dimen name="facet_icon_size">30dp</dimen>
- <dimen name="facet_icon_margin">5dp</dimen>
- <!-- Gears -->
- <dimen name="gear_text_size">28sp</dimen>
- <dimen name="gear_icon_margin">5dp</dimen>
- <!-- Information space -->
- <dimen name="info_height">100dp</dimen>
- <dimen name="info_label_text_size">10sp</dimen>
- <dimen name="info_value_text_size">20sp</dimen>
-
- <!-- -->
- <!-- Navigation state componenets -->
- <!-- -->
- <dimen name="nav_state_width">170dp</dimen>
- <!-- Maneuver -->
- <dimen name="maneuver_width">60dp</dimen>
- <dimen name="maneuver_height">60dp</dimen>
- <dimen name="maneuver_margin">8dp</dimen>
- <dimen name="provided_maneuver_width">30dp</dimen>
- <dimen name="provided_maneuver_height">30dp</dimen>
- <!-- Distance -->
- <dimen name="distance_width">125dp</dimen>
- <dimen name="distance_text_size">20sp</dimen>
- <!-- Segment -->
- <dimen name="segment_text_size">15sp</dimen>
- <!-- ETA -->
- <dimen name="eta_margin_right">15dp</dimen>
- <dimen name="eta_text_size">15sp</dimen>
- <!-- Cue -->
- <dimen name="cue_text_size">15sp</dimen>
- <!-- Lane -->
- <dimen name="laneview_height">25dp</dimen>
- <dimen name="provided_laneview_height">25dp</dimen>
- <dimen name="lane_width">50dp</dimen>
- <dimen name="lane_height">50dp</dimen>
-
- <dimen name="lane_icon_offset">12.5dp</dimen>
-
- <!-- -->
- <!-- Sensor value conversion constants -->
- <!-- -->
- <!-- Speed: meters per second to kilometers per hour -->
- <item name="speed_factor" format="float" type="dimen">3.6</item>
- <!-- Distance: kilometers to meters -->
- <item name="distance_factor" format="float" type="dimen">1000</item>
-
- <!-- fragment_metadata.xml -->
- <dimen name="fragment_metadata_queue_divider_margin">@*android:dimen/car_keyline_1</dimen>
- <dimen name="fragment_metadata_queue_margin_top">@*android:dimen/car_padding_4</dimen>
- <dimen name="fragment_metadata_metadata_margin_start">@*android:dimen/car_padding_4</dimen>
- <dimen name="fragment_metadata_metadata_margin_end">@*android:dimen/car_keyline_1</dimen>
- <dimen name="fragment_metadata_art_margin_start">@*android:dimen/car_keyline_1</dimen>
- <dimen name="fragment_metadata_art_margin_end">@*android:dimen/car_padding_4</dimen>
-
- <!-- metadata_normal.xml -->
- <dimen name="metadata_normal_subtitle_margin_top">@*android:dimen/car_padding_1</dimen>
- <dimen name="metadata_normal_time_margin_top">@*android:dimen/car_padding_1</dimen>
- <dimen name="metadata_normal_seek_margin_top">@*android:dimen/car_padding_4</dimen>
- <dimen name="metadata_normal_subtitle_margin_end">@*android:dimen/car_padding_3</dimen>
-
- <!-- Size of the album art thumbnail -->
- <dimen name="playback_album_art_size_normal">156dp</dimen>
-
- <!-- Playback seekbar track height -->
- <dimen name="playback_seekbar_track_height">8dp</dimen>
-
- <!-- Paddings of playback seekbar -->
- <dimen name="playback_seekbar_padding_start">10dp</dimen>
- <dimen name="playback_seekbar_padding_end">10dp</dimen>
-
- <!-- Size of the thumb in the playback seekbar -->
- <dimen name="playback_seekbar_thumb_height">20dp</dimen>
- <dimen name="playback_seekbar_thumb_width">20dp</dimen>
-
- <!-- fragment_playback.xml and fragment_playback_with_queue.xml -->
- <dimen name="fragment_playback_guide_margin_x">@*android:dimen/car_margin</dimen>
- <dimen name="fragment_playback_guide_margin_top">@*android:dimen/car_padding_4</dimen>
-
- <!-- -->
- <!-- Communication Facet -->
- <!-- -->
- <dimen name="user_profile_title_padding_top">@*android:dimen/car_padding_3</dimen>
- <dimen name="user_profile_body_padding_top">@*android:dimen/car_padding_3</dimen>
-
- <dimen name="large_avatar_icon_size">@dimen/car_large_avatar_size</dimen>
-</resources>
diff --git a/tests/DirectRenderingClusterSample/res/values/strings.xml b/tests/DirectRenderingClusterSample/res/values/strings.xml
deleted file mode 100644
index 5ec6198..0000000
--- a/tests/DirectRenderingClusterSample/res/values/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<resources>
- <string name="app_name" translatable="false">Fake Cluster Implementation</string>
-
- <!-- TODO: Remove or change this placeholder text -->
- <string name="hello_blank_fragment" translatable="false">Hello blank fragment</string>
-
- <!-- Message to show when a navigation app hasn't been selected yet. [CHAR LIMIT=100] -->
- <string name="select_nav_app" translatable="false">Select a navigation app on the main unit.</string>
-
- <!-- Gears texts [CHAR LIMIT=1] -->
- <string name="gear_parked" translatable="false">P</string>
- <string name="gear_reverse" translatable="false">R</string>
- <string name="gear_neutral" translatable="false">N</string>
- <string name="gear_drive" translatable="false">D</string>
-
- <!-- Information labels (shown next to driving directions) [CHAR LIMIT=30] -->
- <string name="info_fuel_label" translatable="false">Fuel</string>
- <string name="info_speed_label" translatable="false">Speed</string>
- <string name="info_range_label" translatable="false">Range</string>
- <string name="info_rpm_label" translatable="false">RPM</string>
- <string name="info_value_empty" translatable="false">-</string>
-
- <!-- Marker used to insert images inside rich-text strings. This string is never shown or spoken
- to the user. Instead a image would be rendered in its place -->
- <string name="span_image" translatable="false">[Image]</string>
-</resources>
diff --git a/tests/DirectRenderingClusterSample/res/values/styles.xml b/tests/DirectRenderingClusterSample/res/values/styles.xml
deleted file mode 100644
index cd5f552..0000000
--- a/tests/DirectRenderingClusterSample/res/values/styles.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<resources>
- <style name="noAnimTheme" parent="android:Theme">
- <item name="android:windowAnimationStyle">@null</item>
- </style>
-</resources>
diff --git a/tests/DirectRenderingClusterSample/res/values/themes.xml b/tests/DirectRenderingClusterSample/res/values/themes.xml
deleted file mode 100644
index 972a036..0000000
--- a/tests/DirectRenderingClusterSample/res/values/themes.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
- <style name="Theme.ClusterTheme" parent="@android:style/Theme.Black.NoTitleBar.Fullscreen">
- <item name="android:windowAnimationStyle">@null</item>
- </style>
-</resources>
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ActivityMonitor.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ActivityMonitor.java
deleted file mode 100644
index 6cabd69..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ActivityMonitor.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityManager.StackInfo;
-import android.app.IActivityManager;
-import android.app.IProcessObserver;
-import android.app.TaskStackListener;
-import android.content.ComponentName;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Top activity monitor, allows listeners to be notified when a new activity comes to the foreground
- * on a particular device.
- */
-public class ActivityMonitor {
- private static final String TAG = "Cluster.ActivityMonitor";
-
- /**
- * Listener of activity changes
- */
- public interface ActivityListener {
- /**
- * Invoked when a new activity becomes the top activity on a particular display.
- */
- void onTopActivityChanged(int displayId, @Nullable ComponentName activity);
- }
-
- private IActivityManager mActivityManager;
- // Listeners of top activity changes, indexed by the displayId they are interested on.
- private final Map<Integer, Set<ActivityListener>> mListeners = new HashMap<>();
- private final Handler mHandler = new Handler();
- private final IProcessObserver.Stub mProcessObserver = new IProcessObserver.Stub() {
- @Override
- public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
- notifyTopActivities();
- }
-
- @Override
- public void onForegroundServicesChanged(int pid, int uid, int fgServicetypes) {
- }
-
- @Override
- public void onProcessDied(int pid, int uid) {
- notifyTopActivities();
- }
- };
- private final TaskStackListener mTaskStackListener = new TaskStackListener() {
- @Override
- public void onTaskStackChanged() {
- Log.i(TAG, "onTaskStackChanged");
- notifyTopActivities();
- }
- };
-
- /**
- * Registers a new listener to receive activity updates on a particular display
- *
- * @param displayId identifier of the display to monitor
- * @param listener listener to be notified
- */
- public void addListener(int displayId, ActivityListener listener) {
- mListeners.computeIfAbsent(displayId, k -> new HashSet<>()).add(listener);
- }
-
- /**
- * Unregisters a listener previously registered with {@link #addListener(int, ActivityListener)}
- */
- public void removeListener(int displayId, ActivityListener listener) {
- mListeners.computeIfAbsent(displayId, k -> new HashSet<>()).remove(listener);
- }
-
- /**
- * Starts monitoring activity changes. {@link #stop()} should be invoked to release resources.
- */
- public void start() {
- mActivityManager = ActivityManager.getService();
- // Monitoring both listeners are necessary as there are cases where one listener cannot
- // monitor activity change.
- try {
- mActivityManager.registerProcessObserver(mProcessObserver);
- mActivityManager.registerTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot register activity monitoring", e);
- throw new RuntimeException(e);
- }
- notifyTopActivities();
- }
-
- /**
- * Stops monitoring activity changes. Should be invoked when this monitor is not longer used.
- */
- public void stop() {
- if (mActivityManager == null) {
- return;
- }
- try {
- mActivityManager.unregisterProcessObserver(mProcessObserver);
- mActivityManager.unregisterTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot unregister activity monitoring. Ignoring", e);
- }
- mActivityManager = null;
- }
-
- /**
- * Notifies listeners on changes of top activities. {@link ActivityManager} might trigger
- * updates on threads different than UI.
- */
- private void notifyTopActivities() {
- mHandler.post(() -> {
- try {
- List<StackInfo> infos = mActivityManager.getAllStackInfos();
- for (StackInfo info : infos) {
- Set<ActivityListener> listeners = mListeners.get(info.displayId);
- if (listeners != null && !listeners.isEmpty()) {
- for (ActivityListener listener : listeners) {
- listener.onTopActivityChanged(info.displayId, info.topActivity);
- }
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot getTasks", e);
- }
- });
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/CarInfoFragment.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/CarInfoFragment.java
deleted file mode 100644
index 87d57e5..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/CarInfoFragment.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-package android.car.cluster.sample;
-
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.fragment.app.Fragment;
-
-/**
- * A simple {@link Fragment} subclass.
- */
-public class CarInfoFragment extends Fragment {
-
-
- public CarInfoFragment() {
- // Required empty public constructor
- }
-
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.fragment_car_info, container, false);
- }
-
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ClusterDisplayProvider.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ClusterDisplayProvider.java
deleted file mode 100644
index 007533c..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ClusterDisplayProvider.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.car.cluster.sample;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.SystemProperties;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.Display;
-import android.view.DisplayAddress;
-
-/**
- * This class provides a display for instrument cluster renderer.
- * <p>
- * By default it will try to provide physical secondary display if it is connected, if secondary
- * display is not connected during creation of this class then it will start networked virtual
- * display and listens for incoming connections.
- *
- * @see {@link NetworkedVirtualDisplay}
- */
-public class ClusterDisplayProvider {
- private static final String TAG = "Cluster.DisplayProvider";
-
- private static final String RO_CLUSTER_DISPLAY_PORT = "ro.car.cluster.displayport";
- private static final String PERSIST_CLUSTER_DISPLAY_PORT =
- "persist.car.cluster.displayport";
- private static final int NETWORKED_DISPLAY_WIDTH = 1280;
- private static final int NETWORKED_DISPLAY_HEIGHT = 720;
- private static final int NETWORKED_DISPLAY_DPI = 320;
-
- private final DisplayListener mListener;
- private final DisplayManager mDisplayManager;
-
- private NetworkedVirtualDisplay mNetworkedVirtualDisplay;
- private int mClusterDisplayId = -1;
-
- ClusterDisplayProvider(Context context, DisplayListener clusterDisplayListener) {
- mListener = clusterDisplayListener;
- mDisplayManager = context.getSystemService(DisplayManager.class);
-
- Display clusterDisplay = getInstrumentClusterDisplay(mDisplayManager);
- if (clusterDisplay != null) {
- Log.i(TAG, String.format("Found display: %s (id: %d, owner: %s)",
- clusterDisplay.getName(), clusterDisplay.getDisplayId(),
- clusterDisplay.getOwnerPackageName()));
- mClusterDisplayId = clusterDisplay.getDisplayId();
- clusterDisplayListener.onDisplayAdded(clusterDisplay.getDisplayId());
- trackClusterDisplay(null /* no need to track display by name */);
- } else {
- Log.i(TAG, "No physical cluster display found, starting network display");
- setupNetworkDisplay(context);
- }
- }
-
- private void setupNetworkDisplay(Context context) {
- mNetworkedVirtualDisplay = new NetworkedVirtualDisplay(context,
- NETWORKED_DISPLAY_WIDTH, NETWORKED_DISPLAY_HEIGHT, NETWORKED_DISPLAY_DPI);
- String displayName = mNetworkedVirtualDisplay.start();
- trackClusterDisplay(displayName);
- }
-
- private void trackClusterDisplay(@Nullable String displayName) {
- mDisplayManager.registerDisplayListener(new DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- boolean clusterDisplayAdded = false;
-
- if (displayName == null && mClusterDisplayId == -1) {
- mClusterDisplayId = displayId;
- clusterDisplayAdded = true;
- } else {
- Display display = mDisplayManager.getDisplay(displayId);
- if (display != null && TextUtils.equals(display.getName(), displayName)) {
- mClusterDisplayId = displayId;
- clusterDisplayAdded = true;
- }
- }
-
- if (clusterDisplayAdded) {
- mListener.onDisplayAdded(displayId);
- }
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- if (displayId == mClusterDisplayId) {
- mClusterDisplayId = -1;
- mListener.onDisplayRemoved(displayId);
- }
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- if (displayId == mClusterDisplayId) {
- mListener.onDisplayChanged(displayId);
- }
- }
-
- }, null);
- }
-
- private static Display getInstrumentClusterDisplay(DisplayManager displayManager) {
- Display[] displays = displayManager.getDisplays();
- Log.d(TAG, "There are currently " + displays.length + " displays connected.");
-
- final int displayPortPrimary = 0; // primary port should not be instrument cluster.
- int displayPort = SystemProperties.getInt(PERSIST_CLUSTER_DISPLAY_PORT,
- displayPortPrimary);
- if (displayPort == displayPortPrimary) {
- displayPort = SystemProperties.getInt(RO_CLUSTER_DISPLAY_PORT,
- displayPortPrimary);
- if (displayPort == displayPortPrimary) {
- return null;
- }
- }
- // match port for system display ( = null getOwnerPackageName())
- // with separate check for main display as main display should be never picked up.
- for (Display display : displays) {
- if (display.getDisplayId() != Display.DEFAULT_DISPLAY
- && display.getOwnerPackageName() == null
- && display.getAddress() != null
- && display.getAddress() instanceof DisplayAddress.Physical) {
- final byte port = ((DisplayAddress.Physical) display.getAddress()).getPort();
- if (displayPort == port) {
- return display;
- }
- }
- }
- return null;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "{"
- + " clusterDisplayId = " + mClusterDisplayId
- + "}";
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ClusterRenderingServiceImpl.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ClusterRenderingServiceImpl.java
deleted file mode 100644
index 80a94e1..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ClusterRenderingServiceImpl.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * 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.
- */
-package android.car.cluster.sample;
-
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-
-import static java.lang.Integer.parseInt;
-
-import android.annotation.Nullable;
-import android.app.ActivityOptions;
-import android.car.cluster.ClusterActivityState;
-import android.car.cluster.renderer.InstrumentClusterRenderingService;
-import android.car.cluster.renderer.NavigationRenderer;
-import android.car.navigation.CarNavigationInstrumentCluster;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.util.Log;
-import android.view.Display;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-
-import androidx.car.cluster.navigation.NavigationState;
-import androidx.versionedparcelable.ParcelUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * Implementation of {@link InstrumentClusterRenderingService} which renders an activity on a
- * virtual display that is transmitted to an external screen.
- */
-public class ClusterRenderingServiceImpl extends InstrumentClusterRenderingService implements
- ImageResolver.BitmapFetcher {
- private static final String TAG = "Cluster.SampleService";
-
- private static final int NO_DISPLAY = -1;
-
- static final String LOCAL_BINDING_ACTION = "local";
- static final String NAV_STATE_BUNDLE_KEY = "navstate";
-
- private List<ServiceClient> mClients = new ArrayList<>();
- private ClusterDisplayProvider mDisplayProvider;
- private int mDisplayId = NO_DISPLAY;
- private final IBinder mLocalBinder = new LocalBinder();
- private final ImageResolver mImageResolver = new ImageResolver(this);
-
- public interface ServiceClient {
- void onKeyEvent(KeyEvent keyEvent);
- void onNavigationStateChange(NavigationState navState);
- }
-
- public class LocalBinder extends Binder {
- ClusterRenderingServiceImpl getService() {
- return ClusterRenderingServiceImpl.this;
- }
- }
-
- private final DisplayListener mDisplayListener = new DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- Log.i(TAG, "Cluster display found, displayId: " + displayId);
- mDisplayId = displayId;
- launchMainActivity();
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- Log.w(TAG, "Cluster display has been removed");
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
-
- }
- };
-
- public void setActivityLaunchOptions(int displayId, ClusterActivityState state) {
- ActivityOptions options = displayId != Display.INVALID_DISPLAY
- ? ActivityOptions.makeBasic().setLaunchDisplayId(displayId)
- : null;
- setClusterActivityLaunchOptions(options);
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, String.format("activity options set: %s (displayeId: %d)",
- options, options.getLaunchDisplayId()));
- }
- setClusterActivityState(state);
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, String.format("activity state set: %s", state));
- }
- }
-
- public void registerClient(ServiceClient client) {
- mClients.add(client);
- }
-
- public void unregisterClient(ServiceClient client) {
- mClients.remove(client);
- }
-
- public ImageResolver getImageResolver() {
- return mImageResolver;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- Log.d(TAG, "onBind, intent: " + intent);
- return LOCAL_BINDING_ACTION.equals(intent.getAction())
- ? mLocalBinder
- : super.onBind(intent);
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.d(TAG, "onCreate");
- mDisplayProvider = new ClusterDisplayProvider(this, mDisplayListener);
- }
-
- private void launchMainActivity() {
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchDisplayId(mDisplayId);
- Intent intent = new Intent(this, MainClusterActivity.class);
- intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
- startActivityAsUser(intent, options.toBundle(), UserHandle.SYSTEM);
- Log.i(TAG, String.format("launching main activity: %s (display: %d)", intent, mDisplayId));
- }
-
- @Override
- public void onKeyEvent(KeyEvent keyEvent) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "onKeyEvent, keyEvent: " + keyEvent);
- }
- broadcastClientEvent(client -> client.onKeyEvent(keyEvent));
- }
-
- /**
- * Broadcasts an event to all the registered service clients
- *
- * @param event event to broadcast
- */
- private void broadcastClientEvent(Consumer<ServiceClient> event) {
- for (ServiceClient client : mClients) {
- event.accept(client);
- }
- }
-
- @Override
- public NavigationRenderer getNavigationRenderer() {
- NavigationRenderer navigationRenderer = new NavigationRenderer() {
- @Override
- public CarNavigationInstrumentCluster getNavigationProperties() {
- CarNavigationInstrumentCluster config =
- CarNavigationInstrumentCluster.createCluster(1000);
- Log.d(TAG, "getNavigationProperties, returns: " + config);
- return config;
- }
-
- @Override
- public void onNavigationStateChanged(@Nullable Bundle bundle) {
- try {
- if (bundle == null) {
- return;
- }
- StringBuilder bundleSummary = new StringBuilder();
- bundle.setClassLoader(ParcelUtils.class.getClassLoader());
- NavigationState navState = NavigationState
- .fromParcelable(bundle.getParcelable(NAV_STATE_BUNDLE_KEY));
- bundleSummary.append(navState.toString());
-
- // Update clients
- broadcastClientEvent(client -> client.onNavigationStateChange(navState));
- Log.d(TAG, "onNavigationStateChanged(" + bundleSummary + ")");
- } catch (Exception e) {
- Log.e(TAG, "Error parsing event data (" + bundle + ")", e);
- NavigationState navState = new NavigationState.Builder().build();
- broadcastClientEvent(client -> client.onNavigationStateChange(navState));
- }
- }
- };
-
- Log.i(TAG, "createNavigationRenderer, returns: " + navigationRenderer);
- return navigationRenderer;
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- if (args != null && args.length > 0) {
- execShellCommand(args);
- } else {
- super.dump(fd, writer, args);
- writer.println("DisplayProvider: " + mDisplayProvider);
- }
- }
-
- private void emulateKeyEvent(int keyCode) {
- Log.i(TAG, "emulateKeyEvent, keyCode: " + keyCode);
- long downTime = SystemClock.uptimeMillis();
- long eventTime = SystemClock.uptimeMillis();
- KeyEvent event = obtainKeyEvent(keyCode, downTime, eventTime, KeyEvent.ACTION_DOWN);
- onKeyEvent(event);
-
- eventTime = SystemClock.uptimeMillis();
- event = obtainKeyEvent(keyCode, downTime, eventTime, KeyEvent.ACTION_UP);
- onKeyEvent(event);
- }
-
- private KeyEvent obtainKeyEvent(int keyCode, long downTime, long eventTime, int action) {
- int scanCode = 0;
- if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- scanCode = 108;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- scanCode = 106;
- }
- return KeyEvent.obtain(
- downTime,
- eventTime,
- action,
- keyCode,
- 0 /* repeat */,
- 0 /* meta state */,
- 0 /* deviceId*/,
- scanCode /* scancode */,
- KeyEvent.FLAG_FROM_SYSTEM /* flags */,
- InputDevice.SOURCE_KEYBOARD,
- null /* characters */);
- }
-
- private void execShellCommand(String[] args) {
- Log.i(TAG, "execShellCommand, args: " + Arrays.toString(args));
-
- String command = args[0];
-
- switch (command) {
- case "injectKey": {
- if (args.length > 1) {
- emulateKeyEvent(parseInt(args[1]));
- } else {
- Log.i(TAG, "Not enough arguments");
- }
- break;
- }
- case "destroyOverlayDisplay": {
- Settings.Global.putString(getContentResolver(),
- Global.OVERLAY_DISPLAY_DEVICES, "");
- break;
- }
-
- case "createOverlayDisplay": {
- if (args.length > 1) {
- Settings.Global.putString(getContentResolver(),
- Global.OVERLAY_DISPLAY_DEVICES, args[1]);
- } else {
- Log.i(TAG, "Not enough arguments, expected 2");
- }
- break;
- }
-
- case "setUnobscuredArea": {
- if (args.length > 5) {
- Rect unobscuredArea = new Rect(parseInt(args[2]), parseInt(args[3]),
- parseInt(args[4]), parseInt(args[5]));
- setClusterActivityState(args[1],
- ClusterActivityState.create(true, unobscuredArea).toBundle());
- } else {
- Log.i(TAG, "wrong format, expected: category left top right bottom");
- }
- }
- }
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ClusterViewModel.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ClusterViewModel.java
deleted file mode 100644
index 1cf1b24..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ClusterViewModel.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.annotation.Nullable;
-import android.app.Application;
-import android.car.Car;
-import android.car.CarAppFocusManager;
-import android.car.VehicleAreaType;
-import android.car.cluster.sample.sensors.Sensor;
-import android.car.cluster.sample.sensors.Sensors;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManager;
-import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
-import android.content.ComponentName;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.util.Log;
-import android.util.TypedValue;
-
-import androidx.annotation.NonNull;
-import androidx.core.util.Preconditions;
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.Transformations;
-
-import java.text.DecimalFormat;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * {@link AndroidViewModel} for cluster information.
- */
-public class ClusterViewModel extends AndroidViewModel {
- private static final String TAG = "Cluster.ViewModel";
-
- private static final int PROPERTIES_REFRESH_RATE_UI = 5;
-
- private float mSpeedFactor;
- private float mDistanceFactor;
-
- public enum NavigationActivityState {
- /** No activity has been selected to be displayed on the navigation fragment yet */
- NOT_SELECTED,
- /** An activity has been selected, but it is not yet visible to the user */
- LOADING,
- /** Navigation activity is visible to the user */
- VISIBLE,
- }
-
- private ComponentName mFreeNavigationActivity;
- private ComponentName mCurrentNavigationActivity;
- private final MutableLiveData<NavigationActivityState> mNavigationActivityStateLiveData =
- new MutableLiveData<>();
- private final MutableLiveData<Boolean> mNavigationFocus = new MutableLiveData<>(false);
- private Car mCar;
- private CarAppFocusManager mCarAppFocusManager;
- private CarPropertyManager mCarPropertyManager;
- private Map<Sensor<?>, MutableLiveData<?>> mSensorLiveDatas = new HashMap<>();
-
- private ServiceConnection mCarServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.i(TAG, "onServiceConnected, name: " + name + ", service: " + service);
-
- registerAppFocusListener();
- registerCarPropertiesListener();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.i(TAG, "onServiceDisconnected, name: " + name);
- mCarAppFocusManager = null;
- mCarPropertyManager = null;
- }
- };
-
- private void registerAppFocusListener() {
- mCarAppFocusManager = (CarAppFocusManager) mCar.getCarManager(
- Car.APP_FOCUS_SERVICE);
- if (mCarAppFocusManager != null) {
- mCarAppFocusManager.addFocusListener(
- (appType, active) -> setNavigationFocus(active),
- CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
- } else {
- Log.e(TAG, "onServiceConnected: unable to obtain CarAppFocusManager");
- }
- }
-
- private void registerCarPropertiesListener() {
- Sensors sensors = Sensors.getInstance();
- mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
- for (Integer propertyId : sensors.getPropertyIds()) {
- try {
- mCarPropertyManager.registerCallback(mCarPropertyEventListener,
- propertyId, PROPERTIES_REFRESH_RATE_UI);
- } catch (SecurityException ex) {
- Log.e(TAG, "onServiceConnected: Unable to listen to car property: " + propertyId
- + " sensors: " + sensors.getSensorsForPropertyId(propertyId), ex);
- }
- }
- }
-
- private CarPropertyEventCallback mCarPropertyEventListener = new CarPropertyEventCallback() {
- @Override
- public void onChangeEvent(CarPropertyValue value) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG,
- "CarProperty change: property " + value.getPropertyId() + ", area"
- + value.getAreaId() + ", value: " + value.getValue());
- }
- for (Sensor<?> sensorId : Sensors.getInstance()
- .getSensorsForPropertyId(value.getPropertyId())) {
- if (sensorId.mAreaId == Sensors.GLOBAL_AREA_ID
- || (sensorId.mAreaId & value.getAreaId()) != 0) {
- setSensorValue(sensorId, value);
- }
- }
- }
-
- @Override
- public void onErrorEvent(int propId, int zone) {
- for (Sensor<?> sensorId : Sensors.getInstance().getSensorsForPropertyId(
- propId)) {
- if (sensorId.mAreaId == VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL
- || (sensorId.mAreaId & zone) != 0) {
- setSensorValue(sensorId, null);
- }
- }
- }
-
- private <T> void setSensorValue(Sensor<T> id, CarPropertyValue<?> value) {
- T newValue = value != null ? id.mAdapter.apply(value) : null;
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Sensor " + id.mName + " = " + newValue);
- }
- getSensorMutableLiveData(id).setValue(newValue);
- }
- };
-
- /**
- * New {@link ClusterViewModel} instance
- */
- public ClusterViewModel(@NonNull Application application) {
- super(application);
- mCar = Car.createCar(application, mCarServiceConnection);
- mCar.connect();
-
- TypedValue tv = new TypedValue();
- getApplication().getResources().getValue(R.dimen.speed_factor, tv, true);
- mSpeedFactor = tv.getFloat();
-
- getApplication().getResources().getValue(R.dimen.distance_factor, tv, true);
- mDistanceFactor = tv.getFloat();
- }
-
- @Override
- protected void onCleared() {
- super.onCleared();
- mCar.disconnect();
- mCar = null;
- mCarAppFocusManager = null;
- mCarPropertyManager = null;
- }
-
- /**
- * Returns a {@link LiveData} providing the current state of the activity displayed on the
- * navigation fragment.
- */
- public LiveData<NavigationActivityState> getNavigationActivityState() {
- return mNavigationActivityStateLiveData;
- }
-
- /**
- * Returns a {@link LiveData} indicating whether navigation focus is currently being granted
- * or not. This indicates whether a navigation application is currently providing driving
- * directions.
- */
- public LiveData<Boolean> getNavigationFocus() {
- return mNavigationFocus;
- }
-
- /**
- * Returns a {@link LiveData} that tracks the value of a given car sensor. Each sensor has its
- * own data type. The list of all supported sensors can be found at {@link Sensors}
- *
- * @param sensor sensor to observe
- * @param <T> data type of such sensor
- */
- @SuppressWarnings("unchecked")
- @NonNull
- public <T> LiveData<T> getSensor(@NonNull Sensor<T> sensor) {
- return getSensorMutableLiveData(Preconditions.checkNotNull(sensor));
- }
-
- /**
- * Returns the current value of the sensor, directly from the VHAL.
- *
- * @param sensor sensor to read
- * @param <V> VHAL data type
- * @param <T> data type of such sensor
- */
- @Nullable
- public <T> T getSensorValue(@NonNull Sensor<T> sensor) {
- CarPropertyValue<?> value = mCarPropertyManager
- .getProperty(sensor.mPropertyId, sensor.mAreaId);
- return sensor.mAdapter.apply(value);
- }
-
- /**
- * Returns a {@link LiveData} that tracks the fuel level in a range from 0 to 100.
- */
- public LiveData<Integer> getFuelLevel() {
- return Transformations.map(getSensor(Sensors.SENSOR_FUEL), (fuelValue) -> {
- Float fuelCapacityValue = getSensorValue(Sensors.SENSOR_FUEL_CAPACITY);
- if (fuelValue == null || fuelCapacityValue == null || fuelCapacityValue == 0) {
- return null;
- }
- if (fuelValue < 0.0f) {
- return 0;
- }
- if (fuelValue > fuelCapacityValue) {
- return 100;
- }
- return Math.round(fuelValue / (fuelCapacityValue * 100f));
- });
- }
-
- /**
- * Returns a {@link LiveData} that tracks the RPM x 1000
- */
- public LiveData<String> getRPM() {
- return Transformations.map(getSensor(Sensors.SENSOR_RPM), (rpmValue) -> {
- return new DecimalFormat("#0.0").format(rpmValue / 1000f);
- });
- }
-
- /**
- * Returns a {@link LiveData} that tracks the speed in either mi/h or km/h depending on locale.
- */
- public LiveData<Integer> getSpeed() {
- return Transformations.map(getSensor(Sensors.SENSOR_SPEED), (speedValue) -> {
- return Math.round(speedValue * mSpeedFactor);
- });
- }
-
- /**
- * Returns a {@link LiveData} that tracks the range the vehicle has until it runs out of gas.
- */
- public LiveData<Integer> getRange() {
- return Transformations.map(getSensor(Sensors.SENSOR_FUEL_RANGE), (rangeValue) -> {
- return Math.round(rangeValue / mDistanceFactor);
- });
- }
-
- /**
- * Sets the activity selected to be displayed on the cluster when no driving directions are
- * being provided.
- */
- public void setFreeNavigationActivity(ComponentName activity) {
- if (!Objects.equals(activity, mFreeNavigationActivity)) {
- mFreeNavigationActivity = activity;
- updateNavigationActivityLiveData();
- }
- }
-
- /**
- * Sets the activity currently being displayed on the cluster.
- */
- public void setCurrentNavigationActivity(ComponentName activity) {
- if (!Objects.equals(activity, mCurrentNavigationActivity)) {
- mCurrentNavigationActivity = activity;
- updateNavigationActivityLiveData();
- }
- }
-
- /**
- * Sets whether navigation focus is currently being granted or not.
- */
- public void setNavigationFocus(boolean navigationFocus) {
- if (mNavigationFocus.getValue() == null || mNavigationFocus.getValue() != navigationFocus) {
- mNavigationFocus.setValue(navigationFocus);
- updateNavigationActivityLiveData();
- }
- }
-
- private void updateNavigationActivityLiveData() {
- NavigationActivityState newState = calculateNavigationActivityState();
- if (newState != mNavigationActivityStateLiveData.getValue()) {
- mNavigationActivityStateLiveData.setValue(newState);
- }
- }
-
- private NavigationActivityState calculateNavigationActivityState() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, String.format("Current state: current activity = '%s', free nav activity = "
- + "'%s', focus = %s", mCurrentNavigationActivity,
- mFreeNavigationActivity,
- mNavigationFocus.getValue()));
- }
- if (mNavigationFocus.getValue() != null && mNavigationFocus.getValue()) {
- // Car service controls which activity is displayed while driving, so we assume this
- // has already been taken care of.
- return NavigationActivityState.VISIBLE;
- } else if (mFreeNavigationActivity == null) {
- return NavigationActivityState.NOT_SELECTED;
- } else if (Objects.equals(mFreeNavigationActivity, mCurrentNavigationActivity)) {
- return NavigationActivityState.VISIBLE;
- } else {
- return NavigationActivityState.LOADING;
- }
- }
-
- @SuppressWarnings("unchecked")
- private <T> MutableLiveData<T> getSensorMutableLiveData(Sensor<T> sensor) {
- return (MutableLiveData<T>) mSensorLiveDatas
- .computeIfAbsent(sensor, x -> new MutableLiveData<>());
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/CueView.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/CueView.java
deleted file mode 100644
index d7bbf5f..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/CueView.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.os.Handler;
-import android.text.SpannableStringBuilder;
-import android.text.style.ImageSpan;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.widget.TextView;
-
-import androidx.car.cluster.navigation.ImageReference;
-import androidx.car.cluster.navigation.RichText;
-import androidx.car.cluster.navigation.RichTextElement;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
-
-/**
- * View component that displays the Cue information on the instrument cluster display
- */
-public class CueView extends TextView {
- private static final String TAG = "Cluster.CueView";
-
- private String mImageSpanText;
- private CompletableFuture<?> mFuture;
- private Handler mHandler = new Handler();
- private RichText mContent;
-
- public CueView(Context context) {
- super(context);
- }
-
- public CueView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public CueView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mImageSpanText = context.getString(R.string.span_image);
- }
-
- public void setRichText(RichText richText, ImageResolver imageResolver) {
- if (richText == null) {
- setText(null);
- return;
- }
-
- if (mFuture != null && !Objects.equals(richText, mContent)) {
- mFuture.cancel(true);
- }
-
- List<ImageReference> imageReferences = richText.getElements().stream()
- .filter(element -> element.getImage() != null)
- .map(element -> element.getImage())
- .collect(Collectors.toList());
- mFuture = imageResolver
- .getBitmaps(imageReferences, 0, getLineHeight())
- .thenAccept(bitmaps -> {
- mHandler.post(() -> update(richText, bitmaps));
- mFuture = null;
- })
- .exceptionally(ex -> {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Unable to fetch images for cue: " + richText);
- }
- mHandler.post(() -> update(richText, Collections.emptyMap()));
- return null;
- });
- mContent = richText;
- }
-
- private void update(RichText richText, Map<ImageReference, Bitmap> bitmaps) {
- SpannableStringBuilder builder = new SpannableStringBuilder();
-
- for (RichTextElement element : richText.getElements()) {
- if (element.getImage() != null) {
- Bitmap bitmap = bitmaps.get(element.getImage());
- if (bitmap != null) {
- String imageText = element.getText().isEmpty() ? mImageSpanText :
- element.getText();
- int start = builder.length();
- int end = start + imageText.length();
- builder.append(imageText);
- BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap);
- drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
- builder.setSpan(new ImageSpan(drawable), start, end, 0);
- }
- } else if (!element.getText().isEmpty()) {
- builder.append(element.getText());
- }
- }
-
- setText(builder);
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/HeartBeatLiveData.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/HeartBeatLiveData.java
deleted file mode 100644
index 42116b8..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/HeartBeatLiveData.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.os.Handler;
-import android.os.Looper;
-
-import androidx.lifecycle.LiveData;
-
-/**
- * Emits a true value in a fixed periodical pace. The first beat begins when this live data becomes
- * active.
- *
- * <p> Note that if this heart beat is shared, the time can be less than the given interval between
- * observation and first beat for the second observer.
- */
-public class HeartBeatLiveData extends LiveData<Boolean> {
- private long mPulseRate;
- private Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
-
- public HeartBeatLiveData(long rateInMillis) {
- mPulseRate = rateInMillis;
- }
-
- @Override
- protected void onActive() {
- super.onActive();
- mMainThreadHandler.post(mUpdateDurationRunnable);
- }
-
- @Override
- protected void onInactive() {
- super.onInactive();
- mMainThreadHandler.removeCallbacks(mUpdateDurationRunnable);
- }
-
- private final Runnable mUpdateDurationRunnable = new Runnable() {
- @Override
- public void run() {
- setValue(true);
- mMainThreadHandler.postDelayed(this, mPulseRate);
- }
- };
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ImageResolver.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ImageResolver.java
deleted file mode 100644
index 5e03b9b..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/ImageResolver.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.net.Uri;
-import android.util.Log;
-import android.util.LruCache;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.car.cluster.navigation.ImageReference;
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
-
-/**
- * Class for retrieving bitmap images from a ContentProvider
- */
-public class ImageResolver {
- private static final String TAG = "Cluster.ImageResolver";
- private static final int IMAGE_CACHE_SIZE_BYTES = 4 * 1024 * 1024; /* 4 mb */
-
- private final BitmapFetcher mFetcher;
- private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(
- IMAGE_CACHE_SIZE_BYTES) {
- @Override
- protected int sizeOf(String key, Bitmap value) {
- return value.getByteCount();
- }
- };
-
- public interface BitmapFetcher {
- Bitmap getBitmap(Uri uri);
- }
-
- /**
- * Creates a resolver that delegate the image retrieval to the given fetcher.
- */
- public ImageResolver(BitmapFetcher fetcher) {
- mFetcher = fetcher;
- }
-
- /**
- * Returns a {@link CompletableFuture} that provides a bitmap from a {@link ImageReference}.
- * This image would fit inside the provided size. Either width, height or both should be greater
- * than 0.
- *
- * @param width required width, or 0 if width is flexible based on height.
- * @param height required height, or 0 if height is flexible based on width.
- */
- @NonNull
- public CompletableFuture<Bitmap> getBitmap(@NonNull ImageReference img, int width, int height) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, String.format("Requesting image %s (width: %d, height: %d)",
- img.getRawContentUri(), width, height));
- }
-
- return CompletableFuture.supplyAsync(() -> {
- // Adjust the size to fit in the requested box.
- Point adjusted = getAdjustedSize(img.getOriginalWidth(), img.getOriginalHeight(), width,
- height);
- if (adjusted == null) {
- Log.e(TAG, "The provided image has no original size: " + img.getRawContentUri());
- return null;
- }
- Uri uri = img.getContentUri(adjusted.x, adjusted.y);
- Bitmap bitmap = mCache.get(uri.toString());
- if (bitmap == null) {
- bitmap = mFetcher.getBitmap(uri);
- if (bitmap == null) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Unable to fetch image: " + uri);
- }
- return null;
- }
- if (bitmap.getWidth() != adjusted.x || bitmap.getHeight() != adjusted.y) {
- bitmap = Bitmap.createScaledBitmap(bitmap, adjusted.x, adjusted.y, true);
- }
- mCache.put(uri.toString(), bitmap);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, String.format("Returning image %s (width: %d, height: %d)",
- img.getRawContentUri(), width, height));
- }
- return bitmap != null ? Bitmap.createScaledBitmap(bitmap, adjusted.x, adjusted.y, true)
- : null;
- });
- }
-
- /**
- * Same as {@link #getBitmap(ImageReference, int, int)} but it works on a list of images. The
- * returning {@link CompletableFuture} will contain a map from each {@link ImageReference} to
- * its bitmap. If any image fails to be fetched, the whole future completes exceptionally.
- *
- * @param width required width, or 0 if width is flexible based on height.
- * @param height required height, or 0 if height is flexible based on width.
- */
- @NonNull
- public CompletableFuture<Map<ImageReference, Bitmap>> getBitmaps(
- @NonNull List<ImageReference> imgs, int width, int height) {
- CompletableFuture<Map<ImageReference, Bitmap>> future = new CompletableFuture<>();
-
- Map<ImageReference, CompletableFuture<Bitmap>> bitmapFutures = imgs.stream().collect(
- Collectors.toMap(
- img -> img,
- img -> getBitmap(img, width, height)));
-
- CompletableFuture.allOf(bitmapFutures.values().toArray(new CompletableFuture[0]))
- .thenAccept(v -> {
- Map<ImageReference, Bitmap> bitmaps = bitmapFutures.entrySet().stream()
- .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry
- .getValue().join()));
- future.complete(bitmaps);
- })
- .exceptionally(ex -> {
- future.completeExceptionally(ex);
- return null;
- });
-
- return future;
- }
-
- /**
- * Returns an image size that exactly fits inside a requested box, maintaining an original size
- * aspect ratio.
- *
- * @param originalWidth original width (must be != 0)
- * @param originalHeight original height (must be != 0)
- * @param requestedWidth required width, or 0 if width is flexible based on height.
- * @param requestedHeight required height, or 0 if height is flexible based on width.
- */
- @Nullable
- public Point getAdjustedSize(int originalWidth, int originalHeight, int requestedWidth,
- int requestedHeight) {
- if (originalWidth <= 0 || originalHeight <= 0) {
- return null;
- } else if (requestedWidth == 0 && requestedHeight == 0) {
- throw new IllegalArgumentException("At least one of width or height must be != 0");
- }
- // If width is flexible or if both width and height are set and the original image is wider
- // than the space provided, then scale the width.
- float requiredRatio = requestedHeight > 0 ? ((float) requestedWidth) / requestedHeight : 0;
- float imageRatio = ((float) originalWidth) / originalHeight;
- Point res = new Point(requestedWidth, requestedHeight);
- if (requestedWidth == 0 || (requestedHeight != 0 && imageRatio < requiredRatio)) {
- res.x = (int) (((float) requestedHeight / originalHeight) * originalWidth);
- } else {
- res.y = (int) (((float) requestedWidth / originalWidth) * originalHeight);
- }
- return res;
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/LaneView.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/LaneView.java
deleted file mode 100644
index 1181fa2..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/LaneView.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.VectorDrawable;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import androidx.car.cluster.navigation.ImageReference;
-import androidx.car.cluster.navigation.Lane;
-import androidx.car.cluster.navigation.LaneDirection;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * View component that displays the Lane preview information on the instrument cluster display
- */
-public class LaneView extends LinearLayout {
- private static final String TAG = "Cluster.LaneView";
-
- private Handler mHandler = new Handler();
-
- private ArrayList<Lane> mLanes;
-
- private final int mWidth = (int) getResources().getDimension(R.dimen.lane_width);
- private final int mHeight = (int) getResources().getDimension(R.dimen.lane_height);
- private final int mOffset = (int) getResources().getDimension(R.dimen.lane_icon_offset);
-
- private enum Shift {
- LEFT,
- RIGHT,
- BOTH
- }
-
- public LaneView(Context context) {
- super(context);
- }
-
- public LaneView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public LaneView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public void setLanes(ImageReference imageReference, ImageResolver imageResolver) {
- imageResolver
- .getBitmap(imageReference, 0, getHeight())
- .thenAccept(bitmap -> {
- mHandler.post(() -> {
- removeAllViews();
- ImageView imgView = new ImageView(getContext());
- imgView.setImageBitmap(bitmap);
- imgView.setAdjustViewBounds(true);
- addView(imgView);
- });
- })
- .exceptionally(ex -> {
- removeAllViews();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Unable to fetch image for lane: " + imageReference);
- }
- return null;
- });
- }
-
- public void setLanes(List<Lane> lanes) {
- mLanes = new ArrayList<>(lanes);
- removeAllViews();
-
- // Use drawables for lane directional guidance
- for (Lane lane : mLanes) {
- Bitmap bitmap = combineBitmapFromLane(lane);
- ImageView imgView = new ImageView(getContext());
- imgView.setImageBitmap(bitmap);
- imgView.setAdjustViewBounds(true);
- addView(imgView);
- }
- }
-
- private Bitmap combineBitmapFromLane(Lane lane) {
- if (lane.getDirections().isEmpty()) {
- return null;
- }
-
- Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
-
- Shift shift = getShift(lane);
-
- for (LaneDirection laneDir : lane.getDirections()) {
- if (!laneDir.isHighlighted()) {
- drawToCanvas(laneDir, canvas, false, shift);
- }
- }
-
- for (LaneDirection laneDir : lane.getDirections()) {
- if (laneDir.isHighlighted()) {
- drawToCanvas(laneDir, canvas, true, shift);
- }
- }
-
- return bitmap;
- }
-
- private void drawToCanvas(LaneDirection laneDir, Canvas canvas, boolean isHighlighted,
- Shift shift) {
- int offset = getOffset(laneDir, shift);
- VectorDrawable icon = (VectorDrawable) getLaneIcon(laneDir);
- icon.setBounds(offset, 0, mWidth + offset, mHeight);
- icon.setColorFilter(new PorterDuffColorFilter(isHighlighted
- ? getContext().getColor(R.color.laneDirectionHighlighted)
- : getContext().getColor(R.color.laneDirection),
- PorterDuff.Mode.SRC_ATOP));
- icon.draw(canvas);
- }
-
- /**
- * Determines the offset direction to line up overlapping lane directions.
- */
- private Shift getShift(Lane lane) {
- boolean containsRight = false;
- boolean containsLeft = false;
- boolean containsStraight = false;
-
- for (LaneDirection laneDir : lane.getDirections()) {
- if (laneDir.getShape().equals(LaneDirection.Shape.NORMAL_RIGHT)
- || laneDir.getShape().equals(LaneDirection.Shape.SLIGHT_RIGHT)
- || laneDir.getShape().equals(LaneDirection.Shape.SHARP_RIGHT)
- || laneDir.getShape().equals(LaneDirection.Shape.U_TURN_RIGHT)) {
- containsRight = true;
- }
- if (laneDir.getShape().equals(LaneDirection.Shape.NORMAL_LEFT)
- || laneDir.getShape().equals(LaneDirection.Shape.SLIGHT_LEFT)
- || laneDir.getShape().equals(LaneDirection.Shape.SHARP_LEFT)
- || laneDir.getShape().equals(LaneDirection.Shape.U_TURN_LEFT)) {
- containsLeft = true;
- }
- if (laneDir.getShape().equals(LaneDirection.Shape.STRAIGHT)) {
- containsStraight = true;
- }
- }
-
- if (containsLeft && containsRight) {
- //shift turns outwards
- return Shift.BOTH;
- } else if (containsStraight && containsRight) {
- //shift straight lane dir to the left
- return Shift.LEFT;
- } else if (containsStraight && containsLeft) {
- //shift straight lane dir to the right
- return Shift.RIGHT;
- }
-
- return null;
- }
-
- /**
- * Returns the offset value of the lane direction based on the given shift direction.
- */
- private int getOffset(LaneDirection laneDir, Shift shift) {
- if (shift == Shift.BOTH) {
- if (laneDir.getShape().equals(LaneDirection.Shape.NORMAL_LEFT)
- || laneDir.getShape().equals(LaneDirection.Shape.SLIGHT_LEFT)
- || laneDir.getShape().equals(LaneDirection.Shape.SHARP_LEFT)
- || laneDir.getShape().equals(LaneDirection.Shape.U_TURN_LEFT)) {
- return -mOffset;
- }
- if (laneDir.getShape().equals(LaneDirection.Shape.NORMAL_RIGHT)
- || laneDir.getShape().equals(LaneDirection.Shape.SLIGHT_RIGHT)
- || laneDir.getShape().equals(LaneDirection.Shape.SHARP_RIGHT)
- || laneDir.getShape().equals(LaneDirection.Shape.U_TURN_RIGHT)) {
- return mOffset;
- }
- } else if (shift == Shift.LEFT) {
- if (laneDir.getShape().equals(LaneDirection.Shape.STRAIGHT)) {
- return -mOffset;
- }
- } else if (shift == Shift.RIGHT) {
- if (laneDir.getShape().equals(LaneDirection.Shape.STRAIGHT)) {
- return mOffset;
- }
- }
-
- return 0;
- }
-
- private Drawable getLaneIcon(@Nullable LaneDirection laneDir) {
- if (laneDir == null) {
- return null;
- }
- switch (laneDir.getShape()) {
- case UNKNOWN:
- return null;
- case STRAIGHT:
- return mContext.getDrawable(R.drawable.direction_continue);
- case SLIGHT_LEFT:
- return mContext.getDrawable(R.drawable.direction_turn_slight_left);
- case SLIGHT_RIGHT:
- return mContext.getDrawable(R.drawable.direction_turn_slight_right);
- case NORMAL_LEFT:
- return mContext.getDrawable(R.drawable.direction_turn_left);
- case NORMAL_RIGHT:
- return mContext.getDrawable(R.drawable.direction_turn_right);
- case SHARP_LEFT:
- return mContext.getDrawable(R.drawable.direction_turn_sharp_left);
- case SHARP_RIGHT:
- return mContext.getDrawable(R.drawable.direction_turn_sharp_right);
- case U_TURN_LEFT:
- return mContext.getDrawable(R.drawable.direction_uturn_left);
- case U_TURN_RIGHT:
- return mContext.getDrawable(R.drawable.direction_uturn_right);
- }
- return null;
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/MainClusterActivity.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/MainClusterActivity.java
deleted file mode 100644
index 0bd298c..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/MainClusterActivity.java
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * 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.
- */
-package android.car.cluster.sample;
-
-import static android.car.cluster.sample.ClusterRenderingServiceImpl.LOCAL_BINDING_ACTION;
-import static android.content.Intent.ACTION_USER_SWITCHED;
-import static android.content.Intent.ACTION_USER_UNLOCKED;
-
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.car.Car;
-import android.car.cluster.ClusterActivityState;
-import android.car.cluster.sample.sensors.Sensors;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Display;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.TextView;
-
-import androidx.car.cluster.navigation.NavigationState;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentPagerAdapter;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.ViewModelProviders;
-import androidx.viewpager.widget.ViewPager;
-
-import com.android.car.telephony.common.InMemoryPhoneBook;
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Main activity displayed on the instrument cluster. This activity contains fragments for each of
- * the cluster "facets" (e.g.: navigation, communication, media and car state). Users can navigate
- * to each facet by using the steering wheel buttons.
- * <p>
- * This activity runs on "system user" (see {@link UserHandle#USER_SYSTEM}) but it is visible on
- * all users (the same activity remains active even during user switch).
- * <p>
- * This activity also launches a default navigation app inside a virtual display (which is located
- * inside {@link NavigationFragment}). This navigation app is launched when:
- * <ul>
- * <li>Virtual display for navigation apps is ready.
- * <li>After every user switch.
- * </ul>
- * This is necessary because the navigation app runs under a normal user, and different users will
- * see different instances of the same application, with their own personalized data.
- */
-public class MainClusterActivity extends FragmentActivity implements
- ClusterRenderingServiceImpl.ServiceClient {
- private static final String TAG = "Cluster.MainActivity";
-
- private static final NavigationState NULL_NAV_STATE = new NavigationState.Builder().build();
- private static final int NO_DISPLAY = -1;
-
- private ViewPager mPager;
- private NavStateController mNavStateController;
- private ClusterViewModel mClusterViewModel;
-
- private Map<View, Facet<?>> mButtonToFacet = new HashMap<>();
- private SparseArray<Facet<?>> mOrderToFacet = new SparseArray<>();
-
- private Map<Sensors.Gear, View> mGearsToIcon = new HashMap<>();
- private InputMethodManager mInputMethodManager;
- private ClusterRenderingServiceImpl mService;
- private VirtualDisplay mPendingVirtualDisplay = null;
-
- private static final int NAVIGATION_ACTIVITY_RETRY_INTERVAL_MS = 1000;
-
- private UserReceiver mUserReceiver;
- private ActivityMonitor mActivityMonitor = new ActivityMonitor();
- private final Handler mHandler = new Handler();
- private final Runnable mRetryLaunchNavigationActivity = this::tryLaunchNavigationActivity;
- private int mNavigationDisplayId = NO_DISPLAY;
-
- private int mPreviousFacet;
-
- /**
- * Description of a virtual display
- */
- public static class VirtualDisplay {
- /** Identifier of the display */
- public final int mDisplayId;
- /** Rectangular area inside this display that can be viewed without obstructions */
- public final Rect mUnobscuredBounds;
-
- public VirtualDisplay(int displayId, Rect unobscuredBounds) {
- mDisplayId = displayId;
- mUnobscuredBounds = unobscuredBounds;
- }
- }
-
- private final View.OnFocusChangeListener mFacetButtonFocusListener =
- new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (hasFocus) {
- mPager.setCurrentItem(mButtonToFacet.get(v).mOrder);
- }
- }
- };
-
- private ServiceConnection mClusterRenderingServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.i(TAG, "onServiceConnected, name: " + name + ", service: " + service);
- mService = ((ClusterRenderingServiceImpl.LocalBinder) service).getService();
- mService.registerClient(MainClusterActivity.this);
- mNavStateController.setImageResolver(mService.getImageResolver());
- if (mPendingVirtualDisplay != null) {
- // If haven't reported the virtual display yet, do so on service connect.
- reportNavDisplay(mPendingVirtualDisplay);
- mPendingVirtualDisplay = null;
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.i(TAG, "onServiceDisconnected, name: " + name);
- mService = null;
- mNavStateController.setImageResolver(null);
- onNavigationStateChange(NULL_NAV_STATE);
- }
- };
-
- private ActivityMonitor.ActivityListener mNavigationActivityMonitor = (displayId, activity) -> {
- if (displayId != mNavigationDisplayId) {
- return;
- }
- mClusterViewModel.setCurrentNavigationActivity(activity);
- };
-
- private static class UserReceiver extends BroadcastReceiver {
- private WeakReference<MainClusterActivity> mActivity;
-
- UserReceiver(MainClusterActivity activity) {
- mActivity = new WeakReference<>(activity);
- }
-
- public void register(Context context) {
- IntentFilter intentFilter = new IntentFilter(ACTION_USER_UNLOCKED);
- intentFilter.addAction(ACTION_USER_SWITCHED);
- context.registerReceiver(this, intentFilter);
- }
-
- public void unregister(Context context) {
- context.unregisterReceiver(this);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- MainClusterActivity activity = mActivity.get();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Broadcast received: " + intent);
- }
- activity.tryLaunchNavigationActivity();
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.d(TAG, "onCreate");
- setContentView(R.layout.activity_main);
-
- mInputMethodManager = getSystemService(InputMethodManager.class);
-
- Intent intent = new Intent(this, ClusterRenderingServiceImpl.class);
- intent.setAction(LOCAL_BINDING_ACTION);
- bindServiceAsUser(intent, mClusterRenderingServiceConnection, 0, UserHandle.SYSTEM);
-
- registerFacet(new Facet<>(findViewById(R.id.btn_nav), 0, NavigationFragment.class));
- registerFacet(new Facet<>(findViewById(R.id.btn_phone), 1, PhoneFragment.class));
- registerFacet(new Facet<>(findViewById(R.id.btn_music), 2, MusicFragment.class));
- registerFacet(new Facet<>(findViewById(R.id.btn_car_info), 3, CarInfoFragment.class));
- registerGear(findViewById(R.id.gear_parked), Sensors.Gear.PARK);
- registerGear(findViewById(R.id.gear_reverse), Sensors.Gear.REVERSE);
- registerGear(findViewById(R.id.gear_neutral), Sensors.Gear.NEUTRAL);
- registerGear(findViewById(R.id.gear_drive), Sensors.Gear.DRIVE);
-
- mPager = findViewById(R.id.pager);
- mPager.setAdapter(new ClusterPageAdapter(getSupportFragmentManager()));
- mOrderToFacet.get(0).mButton.requestFocus();
- mNavStateController = new NavStateController(findViewById(R.id.navigation_state));
-
- mClusterViewModel = ViewModelProviders.of(this).get(ClusterViewModel.class);
- mClusterViewModel.getNavigationFocus().observe(this, focus -> {
- // If focus is lost, we launch the default navigation activity again.
- if (!focus) {
- mNavStateController.update(null);
- tryLaunchNavigationActivity();
- }
- });
-
- mClusterViewModel.getSensor(Sensors.SENSOR_GEAR).observe(this, this::updateSelectedGear);
-
- registerSensor(findViewById(R.id.info_fuel), mClusterViewModel.getFuelLevel());
- registerSensor(findViewById(R.id.info_speed), mClusterViewModel.getSpeed());
- registerSensor(findViewById(R.id.info_range), mClusterViewModel.getRange());
- registerSensor(findViewById(R.id.info_rpm), mClusterViewModel.getRPM());
-
- mActivityMonitor.start();
-
- mUserReceiver = new UserReceiver(this);
- mUserReceiver.register(this);
-
- try {
- InMemoryPhoneBook.get();
- } catch (IllegalStateException ex) {
- // Initialize if not yet initialized
- InMemoryPhoneBook.init(this);
- }
-
- PhoneFragmentViewModel phoneViewModel = ViewModelProviders.of(this).get(
- PhoneFragmentViewModel.class);
-
- phoneViewModel.setPhoneStateCallback(new PhoneFragmentViewModel.PhoneStateCallback() {
- @Override
- public void onCall() {
- mPreviousFacet = mPager.getCurrentItem();
- mOrderToFacet.get(1).mButton.requestFocus();
- }
-
- @Override
- public void onDisconnect() {
- mOrderToFacet.get(mPreviousFacet).mButton.requestFocus();
- }
- });
- }
-
- private <V> void registerSensor(TextView textView, LiveData<V> source) {
- String emptyValue = getString(R.string.info_value_empty);
- source.observe(this, value -> textView.setText(value != null
- ? value.toString() : emptyValue));
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- Log.d(TAG, "onDestroy");
- mUserReceiver.unregister(this);
- mActivityMonitor.stop();
- if (mService != null) {
- mService.unregisterClient(this);
- mService = null;
- }
- unbindService(mClusterRenderingServiceConnection);
- }
-
- @Override
- public void onKeyEvent(KeyEvent event) {
- Log.i(TAG, "onKeyEvent, event: " + event);
-
- // This is a hack. We use SOURCE_CLASS_POINTER here because this type of input is associated
- // with the display. otherwise this event will be ignored in ViewRootImpl because injecting
- // KeyEvent w/o activity being focused is useless.
- event.setSource(event.getSource() | InputDevice.SOURCE_CLASS_POINTER);
- mInputMethodManager.dispatchKeyEventFromInputMethod(getCurrentFocus(), event);
- }
-
- @Override
- public void onNavigationStateChange(NavigationState state) {
- Log.d(TAG, "onNavigationStateChange: " + state);
- if (mNavStateController != null) {
- mNavStateController.update(state);
- }
- }
-
- public void updateNavDisplay(VirtualDisplay virtualDisplay) {
- // Starting the default navigation activity. This activity will be shown when navigation
- // focus is not taken.
- startNavigationActivity(virtualDisplay.mDisplayId);
- // Notify the service (so it updates display properties on car service)
- if (mService == null) {
- // Service is not bound yet. Hold the information and notify when the service is bound.
- mPendingVirtualDisplay = virtualDisplay;
- return;
- } else {
- reportNavDisplay(virtualDisplay);
- }
- }
-
- private void reportNavDisplay(VirtualDisplay virtualDisplay) {
- mService.setActivityLaunchOptions(virtualDisplay.mDisplayId, ClusterActivityState
- .create(virtualDisplay.mDisplayId != Display.INVALID_DISPLAY,
- virtualDisplay.mUnobscuredBounds));
- }
-
- public class ClusterPageAdapter extends FragmentPagerAdapter {
- public ClusterPageAdapter(FragmentManager fm) {
- super(fm);
- }
-
- @Override
- public int getCount() {
- return mButtonToFacet.size();
- }
-
- @Override
- public Fragment getItem(int position) {
- return mOrderToFacet.get(position).getOrCreateFragment();
- }
- }
-
- private <T> void registerFacet(Facet<T> facet) {
- mOrderToFacet.append(facet.mOrder, facet);
- mButtonToFacet.put(facet.mButton, facet);
-
- facet.mButton.setOnFocusChangeListener(mFacetButtonFocusListener);
- }
-
- private static class Facet<T> {
- Button mButton;
- Class<T> mClazz;
- int mOrder;
-
- Facet(Button button, int order, Class<T> clazz) {
- this.mButton = button;
- this.mOrder = order;
- this.mClazz = clazz;
- }
-
- private Fragment mFragment;
-
- Fragment getOrCreateFragment() {
- if (mFragment == null) {
- try {
- mFragment = (Fragment) mClazz.getConstructors()[0].newInstance();
- } catch (InstantiationException | IllegalAccessException
- | InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- }
- return mFragment;
- }
- }
-
- private void startNavigationActivity(int displayId) {
- mActivityMonitor.removeListener(mNavigationDisplayId, mNavigationActivityMonitor);
- mActivityMonitor.addListener(displayId, mNavigationActivityMonitor);
- mNavigationDisplayId = displayId;
- tryLaunchNavigationActivity();
- }
-
- /**
- * Tries to start a default navigation activity in the cluster. During system initialization
- * launching user activities might fail due the system not being ready or {@link PackageManager}
- * not being able to resolve the implicit intent. It is also possible that the system doesn't
- * have a default navigation activity selected yet.
- */
- private void tryLaunchNavigationActivity() {
- if (mNavigationDisplayId == NO_DISPLAY) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, String.format("Launch activity ignored (no display yet)"));
- }
- // Not ready to launch yet.
- return;
- }
- mHandler.removeCallbacks(mRetryLaunchNavigationActivity);
-
- ComponentName navigationActivity = getNavigationActivity();
- mClusterViewModel.setFreeNavigationActivity(navigationActivity);
-
- try {
- if (navigationActivity == null) {
- throw new ActivityNotFoundException();
- }
- Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Car.CAR_CATEGORY_NAVIGATION)
- .setPackage(navigationActivity.getPackageName())
- .setComponent(navigationActivity)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- Log.d(TAG, "Launching: " + intent + " on display: " + mNavigationDisplayId);
- Bundle activityOptions = ActivityOptions.makeBasic()
- .setLaunchDisplayId(mNavigationDisplayId)
- .toBundle();
-
- startActivityAsUser(intent, activityOptions, UserHandle.CURRENT);
- } catch (ActivityNotFoundException ex) {
- // Some activities might not be available right on startup. We will retry.
- mHandler.postDelayed(mRetryLaunchNavigationActivity,
- NAVIGATION_ACTIVITY_RETRY_INTERVAL_MS);
- } catch (Exception ex) {
- Log.e(TAG, "Unable to start navigation activity: " + navigationActivity, ex);
- }
- }
-
- /**
- * Returns a default navigation activity to show in the cluster.
- * In the current implementation we search for an activity with the
- * {@link Car#CAR_CATEGORY_NAVIGATION} category from the same navigation app
- * selected from CarLauncher (see CarLauncher#getMapsIntent()).
- * Alternatively, other implementations could:
- * <ul>
- * <li>Read this package from a resource (having a OEM default activity to show)
- * <li>Let the user select one from settings.
- * </ul>
- */
- private ComponentName getNavigationActivity() {
- PackageManager pm = getPackageManager();
- int userId = ActivityManager.getCurrentUser();
-
- // Get currently selected navigation app.
- Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
- Intent.CATEGORY_APP_MAPS);
- ResolveInfo navigationApp = pm.resolveActivityAsUser(intent,
- PackageManager.MATCH_DEFAULT_ONLY, userId);
-
- // Get all possible cluster activities
- intent = new Intent(Intent.ACTION_MAIN).addCategory(Car.CAR_CATEGORY_NAVIGATION);
- List<ResolveInfo> candidates = pm.queryIntentActivitiesAsUser(intent, 0, userId);
-
- // If there is a select navigation app, try finding a matching auxiliary navigation activity
- if (navigationApp != null) {
- for (ResolveInfo candidate : candidates) {
- if (candidate.activityInfo.packageName.equals(navigationApp.activityInfo
- .packageName)) {
- Log.d(TAG, "Found activity: " + candidate);
- return new ComponentName(candidate.activityInfo.packageName,
- candidate.activityInfo.name);
- }
- }
- }
-
- // During initialization implicit intents might not provided a result. We will just
- // retry until we find one, or we exhaust the retries.
- Log.d(TAG, "No default activity found (it might not be available yet).");
- return null;
- }
-
- private void registerGear(View view, Sensors.Gear gear) {
- mGearsToIcon.put(gear, view);
- }
-
- private void updateSelectedGear(Sensors.Gear gear) {
- for (Map.Entry<Sensors.Gear, View> entry : mGearsToIcon.entrySet()) {
- entry.getValue().setSelected(entry.getKey() == gear);
- }
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/MusicFragment.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/MusicFragment.java
deleted file mode 100644
index 25739e2..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/MusicFragment.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-import androidx.lifecycle.ViewModelProviders;
-
-import com.android.car.apps.common.BackgroundImageView;
-import com.android.car.media.common.playback.PlaybackViewModel;
-import com.android.car.media.common.source.MediaSourceViewModel;
-
-/**
- * Displays information on the current media item selected.
- */
-public class MusicFragment extends Fragment {
- private static final String TAG = "MusicFragment";
-
- public MusicFragment() {
- // Required empty public constructor
- }
-
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
- Bundle savedInstanceState) {
- FragmentActivity activity = requireActivity();
- PlaybackViewModel playbackViewModel = PlaybackViewModel.get(activity.getApplication());
- MediaSourceViewModel mMediaSourceViewModel = MediaSourceViewModel.get(
- activity.getApplication());
-
- MusicFragmentViewModel innerViewModel = ViewModelProviders.of(activity).get(
- MusicFragmentViewModel.class);
- innerViewModel.init(mMediaSourceViewModel, playbackViewModel);
-
- View view = inflater.inflate(R.layout.fragment_music, container, false);
-
- TextView appName = view.findViewById(R.id.app_name);
- innerViewModel.getAppName().observe(getViewLifecycleOwner(), appName::setText);
-
- TextView title = view.findViewById(R.id.title);
- innerViewModel.getTitle().observe(getViewLifecycleOwner(), title::setText);
-
- TextView subtitle = view.findViewById(R.id.subtitle);
- innerViewModel.getSubtitle().observe(getViewLifecycleOwner(), subtitle::setText);
-
- SeekBar seekBar = view.findViewById(R.id.seek_bar);
- innerViewModel.getMaxProgress().observe(getViewLifecycleOwner(),
- maxProgress -> seekBar.setMax(maxProgress != null ? maxProgress.intValue() : 0));
- innerViewModel.getProgress().observe(getViewLifecycleOwner(),
- progress -> seekBar.setProgress((int) progress.getProgress()));
- innerViewModel.hasTime().observe(getViewLifecycleOwner(),
- hasTime -> seekBar.setVisibility(hasTime ? View.VISIBLE : View.INVISIBLE));
-
- TextView time = view.findViewById(R.id.time);
-
- innerViewModel.getTimeText().observe(getViewLifecycleOwner(),
- timeText -> time.setText(timeText));
-
- BackgroundImageView albumBackground = view.findViewById(R.id.album_background);
- ImageView albumIcon = view.findViewById(R.id.album_art);
- innerViewModel.getAlbumArt().observe(getViewLifecycleOwner(), albumArt -> {
- albumBackground.setBackgroundImage(albumArt, true);
- if (albumArt == null) {
- albumIcon.setImageDrawable(getContext().getDrawable(R.drawable.ic_person));
- } else {
- albumIcon.setImageBitmap(albumArt);
- }
- });
-
- return view;
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/MusicFragmentViewModel.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/MusicFragmentViewModel.java
deleted file mode 100644
index 81a87df..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/MusicFragmentViewModel.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import static androidx.lifecycle.Transformations.map;
-
-import static com.android.car.arch.common.LiveDataFunctions.combine;
-import static com.android.car.arch.common.LiveDataFunctions.mapNonNull;
-
-import android.annotation.SuppressLint;
-import android.app.Application;
-import android.graphics.Bitmap;
-import android.media.session.PlaybackState;
-
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-
-import com.android.car.media.common.MediaItemMetadata;
-import com.android.car.media.common.playback.AlbumArtLiveData;
-import com.android.car.media.common.playback.PlaybackProgress;
-import com.android.car.media.common.playback.PlaybackViewModel;
-import com.android.car.media.common.source.MediaSource;
-import com.android.car.media.common.source.MediaSourceViewModel;
-
-import com.bumptech.glide.request.target.Target;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * View model for {@link MusicFragment}
- */
-public final class MusicFragmentViewModel extends AndroidViewModel {
-
- private LiveData<MediaSource> mMediaSource;
- private LiveData<CharSequence> mAppName;
- private LiveData<Bitmap> mAppIcon;
- private LiveData<CharSequence> mTitle;
- private LiveData<CharSequence> mSubtitle;
- private LiveData<Bitmap> mAlbumArt;
- private LiveData<PlaybackProgress> mProgress;
- private LiveData<Long> mMaxProgress;
- private LiveData<CharSequence> mTimeText;
- private LiveData<Boolean> mHasTime;
-
- private PlaybackViewModel mPlaybackViewModel;
- private MediaSourceViewModel mMediaSourceViewModel;
-
- public MusicFragmentViewModel(Application application) {
- super(application);
- }
-
- void init(MediaSourceViewModel mediaSourceViewModel, PlaybackViewModel playbackViewModel) {
- if (mMediaSourceViewModel == mediaSourceViewModel
- && mPlaybackViewModel == playbackViewModel) {
- return;
- }
- mPlaybackViewModel = playbackViewModel;
- mMediaSourceViewModel = mediaSourceViewModel;
- mMediaSource = mMediaSourceViewModel.getPrimaryMediaSource();
- mAppName = mapNonNull(mMediaSource, MediaSource::getName);
- mAppIcon = mapNonNull(mMediaSource, MediaSource::getRoundPackageIcon);
- mTitle = mapNonNull(playbackViewModel.getMetadata(), MediaItemMetadata::getTitle);
- mSubtitle = mapNonNull(playbackViewModel.getMetadata(), MediaItemMetadata::getSubtitle);
- mAlbumArt = AlbumArtLiveData.getAlbumArt(getApplication(),
- Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL, false,
- playbackViewModel.getMetadata());
- mProgress = playbackViewModel.getProgress();
- mMaxProgress = map(playbackViewModel.getPlaybackStateWrapper(),
- state -> state != null ? state.getMaxProgress() : 0L);
- mTimeText = combine(mProgress, mMaxProgress, (progress, maxProgress) -> {
- boolean showHours = TimeUnit.MILLISECONDS.toHours(maxProgress) > 0;
- return String.format("%s / %s",
- formatTime(progress.getProgress(), showHours),
- formatTime(maxProgress, showHours));
- });
- mHasTime = combine(mProgress, mMaxProgress, (progress, maxProgress) ->
- maxProgress > 0
- && progress.getProgress() != PlaybackState.PLAYBACK_POSITION_UNKNOWN);
- }
-
- LiveData<CharSequence> getAppName() {
- return mAppName;
- }
-
- LiveData<Bitmap> getAppIcon() {
- return mAppIcon;
- }
-
- LiveData<CharSequence> getTitle() {
- return mTitle;
- }
-
- LiveData<CharSequence> getSubtitle() {
- return mSubtitle;
- }
-
- LiveData<Bitmap> getAlbumArt() {
- return mAlbumArt;
- }
-
- LiveData<PlaybackProgress> getProgress() {
- return mProgress;
- }
-
- LiveData<Long> getMaxProgress() {
- return mMaxProgress;
- }
-
- LiveData<CharSequence> getTimeText() {
- return mTimeText;
- }
-
- LiveData<Boolean> hasTime() {
- return mHasTime;
- }
-
- @SuppressLint("DefaultLocale")
- private static String formatTime(long millis, boolean showHours) {
- long hours = TimeUnit.MILLISECONDS.toHours(millis);
- long minutes = TimeUnit.MILLISECONDS.toMinutes(millis) % TimeUnit.HOURS.toMinutes(1);
- long seconds = TimeUnit.MILLISECONDS.toSeconds(millis) % TimeUnit.MINUTES.toSeconds(1);
- if (showHours) {
- return String.format("%d:%02d:%02d", hours, minutes, seconds);
- } else {
- return String.format("%d:%02d", minutes, seconds);
- }
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/NavStateController.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/NavStateController.java
deleted file mode 100644
index bb39e63..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/NavStateController.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.util.Log;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.car.cluster.navigation.Destination;
-import androidx.car.cluster.navigation.Destination.Traffic;
-import androidx.car.cluster.navigation.Distance;
-import androidx.car.cluster.navigation.ImageReference;
-import androidx.car.cluster.navigation.Maneuver;
-import androidx.car.cluster.navigation.NavigationState;
-import androidx.car.cluster.navigation.Segment;
-import androidx.car.cluster.navigation.Step;
-
-import java.time.Duration;
-import java.time.ZonedDateTime;
-
-/**
- * View controller for navigation state rendering.
- */
-public class NavStateController {
- private static final String TAG = "Cluster.NavController";
-
- private Handler mHandler = new Handler();
-
- private ImageView mManeuver;
- private ImageView mProvidedManeuver;
- private LaneView mLane;
- private LaneView mProvidedLane;
- private TextView mDistance;
- private TextView mSegment;
- private TextView mEta;
- private CueView mCue;
- private Context mContext;
- private ImageResolver mImageResolver;
-
- /**
- * Creates a controller to coordinate updates to the views displaying navigation state
- * data.
- *
- * @param container {@link View} containing the navigation state views
- */
- public NavStateController(View container) {
- mManeuver = container.findViewById(R.id.maneuver);
- mProvidedManeuver = container.findViewById(R.id.provided_maneuver);
- mLane = container.findViewById(R.id.lane);
- mProvidedLane = container.findViewById(R.id.provided_lane);
- mDistance = container.findViewById(R.id.distance);
- mSegment = container.findViewById(R.id.segment);
- mEta = container.findViewById(R.id.eta);
- mCue = container.findViewById(R.id.cue);
-
- mContext = container.getContext();
- }
-
- public void setImageResolver(@Nullable ImageResolver imageResolver) {
- mImageResolver = imageResolver;
- }
-
- /**
- * Updates views to reflect the provided navigation state
- */
- public void update(@Nullable NavigationState state) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Updating nav state: " + state);
- }
- Step step = state != null && state.getSteps().size() > 0 ? state.getSteps().get(0) : null;
- Destination destination = state != null && !state.getDestinations().isEmpty()
- ? state.getDestinations().get(0) : null;
- ZonedDateTime eta = destination != null ? destination.getEta() : null;
- Traffic traffic = destination != null ? destination.getTraffic() : null;
-
- mEta.setText(eta != null ? formatEta(eta) : null);
- mEta.setTextColor(getTrafficColor(traffic));
- mManeuver.setImageDrawable(getManeuverIcon(step != null ? step.getManeuver() : null));
- setProvidedManeuverIcon(mProvidedManeuver,
- step != null ? step.getManeuver().getIcon() : null);
- mDistance.setText(formatDistance(step != null ? step.getDistance() : null));
- mSegment.setText(state != null ? getSegmentString(state.getCurrentSegment()) : null);
- mCue.setRichText(step != null ? step.getCue() : null, mImageResolver);
-
- if (step != null && step.getLanes().size() > 0) {
- mProvidedLane.setLanes(step.getLanesImage(), mImageResolver);
- mProvidedLane.setVisibility(View.VISIBLE);
-
- mLane.setLanes(step.getLanes());
- mLane.setVisibility(View.VISIBLE);
- } else {
- mLane.setVisibility(View.GONE);
- mProvidedLane.setVisibility(View.GONE);
- }
- }
-
-
- private int getTrafficColor(@Nullable Traffic traffic) {
- if (traffic == Traffic.LOW) {
- return mContext.getColor(R.color.low_traffic);
- } else if (traffic == Traffic.MEDIUM) {
- return mContext.getColor(R.color.medium_traffic);
- } else if (traffic == Traffic.HIGH) {
- return mContext.getColor(R.color.high_traffic);
- }
-
- return mContext.getColor(R.color.unknown_traffic);
- }
-
- private String formatEta(@Nullable ZonedDateTime eta) {
- ZonedDateTime now = ZonedDateTime.now();
- Duration duration = Duration.between(now, eta);
- long seconds = duration.getSeconds();
-
- // TODO: move formatting into common lib somewhere
- long minutes = (seconds / 60) % 60;
- long hours = (seconds / 3600) % 24;
- long days = seconds / (3600 * 24);
-
- if (days > 0) {
- return String.format("%d d %d hr", days, hours);
- } else if (hours > 0) {
- return String.format("%d hr %d min", hours, minutes);
- } else {
- return String.format("%d min", minutes);
- }
- }
-
- private String getSegmentString(Segment segment) {
- if (segment != null) {
- return segment.getName();
- }
-
- return null;
- }
-
- private void setProvidedManeuverIcon(ImageView view, ImageReference imageReference) {
- if (mImageResolver == null || imageReference == null) {
- view.setImageBitmap(null);
- return;
- }
-
- mImageResolver
- .getBitmap(imageReference, 0, view.getHeight())
- .thenAccept(bitmap -> {
- mHandler.post(() -> {
- view.setImageBitmap(bitmap);
- });
- })
- .exceptionally(ex -> {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Unable to fetch image for maneuver: " + imageReference);
- }
- return null;
- });
- }
-
- private Drawable getManeuverIcon(@Nullable Maneuver maneuver) {
- if (maneuver == null) {
- return null;
- }
- switch (maneuver.getType()) {
- case UNKNOWN:
- return null;
- case DEPART:
- return mContext.getDrawable(R.drawable.direction_depart);
- case NAME_CHANGE:
- return mContext.getDrawable(R.drawable.direction_new_name_straight);
- case KEEP_LEFT:
- return mContext.getDrawable(R.drawable.direction_continue_left);
- case KEEP_RIGHT:
- return mContext.getDrawable(R.drawable.direction_continue_right);
- case TURN_SLIGHT_LEFT:
- return mContext.getDrawable(R.drawable.direction_turn_slight_left);
- case TURN_SLIGHT_RIGHT:
- return mContext.getDrawable(R.drawable.direction_turn_slight_right);
- case TURN_NORMAL_LEFT:
- return mContext.getDrawable(R.drawable.direction_turn_left);
- case TURN_NORMAL_RIGHT:
- return mContext.getDrawable(R.drawable.direction_turn_right);
- case TURN_SHARP_LEFT:
- return mContext.getDrawable(R.drawable.direction_turn_sharp_left);
- case TURN_SHARP_RIGHT:
- return mContext.getDrawable(R.drawable.direction_turn_sharp_right);
- case U_TURN_LEFT:
- return mContext.getDrawable(R.drawable.direction_uturn_left);
- case U_TURN_RIGHT:
- return mContext.getDrawable(R.drawable.direction_uturn_right);
- case ON_RAMP_SLIGHT_LEFT:
- return mContext.getDrawable(R.drawable.direction_on_ramp_slight_left);
- case ON_RAMP_SLIGHT_RIGHT:
- return mContext.getDrawable(R.drawable.direction_on_ramp_slight_right);
- case ON_RAMP_NORMAL_LEFT:
- return mContext.getDrawable(R.drawable.direction_on_ramp_left);
- case ON_RAMP_NORMAL_RIGHT:
- return mContext.getDrawable(R.drawable.direction_on_ramp_right);
- case ON_RAMP_SHARP_LEFT:
- return mContext.getDrawable(R.drawable.direction_on_ramp_sharp_left);
- case ON_RAMP_SHARP_RIGHT:
- return mContext.getDrawable(R.drawable.direction_on_ramp_sharp_right);
- case ON_RAMP_U_TURN_LEFT:
- return mContext.getDrawable(R.drawable.direction_uturn_left);
- case ON_RAMP_U_TURN_RIGHT:
- return mContext.getDrawable(R.drawable.direction_uturn_right);
- case OFF_RAMP_SLIGHT_LEFT:
- return mContext.getDrawable(R.drawable.direction_off_ramp_slight_left);
- case OFF_RAMP_SLIGHT_RIGHT:
- return mContext.getDrawable(R.drawable.direction_off_ramp_slight_right);
- case OFF_RAMP_NORMAL_LEFT:
- return mContext.getDrawable(R.drawable.direction_off_ramp_left);
- case OFF_RAMP_NORMAL_RIGHT:
- return mContext.getDrawable(R.drawable.direction_off_ramp_right);
- case FORK_LEFT:
- return mContext.getDrawable(R.drawable.direction_fork_left);
- case FORK_RIGHT:
- return mContext.getDrawable(R.drawable.direction_fork_right);
- case MERGE_LEFT:
- return mContext.getDrawable(R.drawable.direction_merge_left);
- case MERGE_RIGHT:
- return mContext.getDrawable(R.drawable.direction_merge_right);
- case ROUNDABOUT_ENTER:
- return mContext.getDrawable(R.drawable.direction_roundabout);
- case ROUNDABOUT_EXIT:
- return mContext.getDrawable(R.drawable.direction_roundabout);
- case ROUNDABOUT_ENTER_AND_EXIT_CW_SHARP_RIGHT:
- return mContext.getDrawable(R.drawable.direction_roundabout_cw_sharp_right);
- case ROUNDABOUT_ENTER_AND_EXIT_CW_NORMAL_RIGHT:
- return mContext.getDrawable(R.drawable.direction_roundabout_cw_right);
- case ROUNDABOUT_ENTER_AND_EXIT_CW_SLIGHT_RIGHT:
- return mContext.getDrawable(R.drawable.direction_roundabout_cw_slight_right);
- case ROUNDABOUT_ENTER_AND_EXIT_CW_STRAIGHT:
- return mContext.getDrawable(R.drawable.direction_roundabout_cw_straight);
- case ROUNDABOUT_ENTER_AND_EXIT_CW_SHARP_LEFT:
- return mContext.getDrawable(R.drawable.direction_roundabout_cw_sharp_left);
- case ROUNDABOUT_ENTER_AND_EXIT_CW_NORMAL_LEFT:
- return mContext.getDrawable(R.drawable.direction_roundabout_cw_left);
- case ROUNDABOUT_ENTER_AND_EXIT_CW_SLIGHT_LEFT:
- return mContext.getDrawable(R.drawable.direction_roundabout_cw_slight_left);
- case ROUNDABOUT_ENTER_AND_EXIT_CW_U_TURN:
- return mContext.getDrawable(R.drawable.direction_uturn_right);
- case ROUNDABOUT_ENTER_AND_EXIT_CCW_SHARP_RIGHT:
- return mContext.getDrawable(R.drawable.direction_roundabout_ccw_sharp_right);
- case ROUNDABOUT_ENTER_AND_EXIT_CCW_NORMAL_RIGHT:
- return mContext.getDrawable(R.drawable.direction_roundabout_ccw_right);
- case ROUNDABOUT_ENTER_AND_EXIT_CCW_SLIGHT_RIGHT:
- return mContext.getDrawable(R.drawable.direction_roundabout_ccw_slight_right);
- case ROUNDABOUT_ENTER_AND_EXIT_CCW_STRAIGHT:
- return mContext.getDrawable(R.drawable.direction_roundabout_ccw_straight);
- case ROUNDABOUT_ENTER_AND_EXIT_CCW_SHARP_LEFT:
- return mContext.getDrawable(R.drawable.direction_roundabout_ccw_sharp_left);
- case ROUNDABOUT_ENTER_AND_EXIT_CCW_NORMAL_LEFT:
- return mContext.getDrawable(R.drawable.direction_roundabout_ccw_left);
- case ROUNDABOUT_ENTER_AND_EXIT_CCW_SLIGHT_LEFT:
- return mContext.getDrawable(R.drawable.direction_roundabout_ccw_slight_left);
- case ROUNDABOUT_ENTER_AND_EXIT_CCW_U_TURN:
- return mContext.getDrawable(R.drawable.direction_uturn_left);
- case STRAIGHT:
- return mContext.getDrawable(R.drawable.direction_continue);
- case FERRY_BOAT:
- return mContext.getDrawable(R.drawable.direction_close);
- case FERRY_TRAIN:
- return mContext.getDrawable(R.drawable.direction_close);
- case DESTINATION:
- return mContext.getDrawable(R.drawable.direction_arrive);
- case DESTINATION_STRAIGHT:
- return mContext.getDrawable(R.drawable.direction_arrive_straight);
- case DESTINATION_LEFT:
- return mContext.getDrawable(R.drawable.direction_arrive_left);
- case DESTINATION_RIGHT:
- return mContext.getDrawable(R.drawable.direction_arrive_right);
- }
- return null;
- }
-
- private String formatDistance(@Nullable Distance distance) {
- if (distance == null || distance.getDisplayUnit() == Distance.Unit.UNKNOWN) {
- return null;
- }
-
- String unit = "";
-
- switch (distance.getDisplayUnit()) {
- case METERS:
- unit = "m";
- break;
- case KILOMETERS:
- unit = "km";
- break;
- case MILES:
- unit = "mi";
- break;
- case YARDS:
- unit = "yd";
- break;
- case FEET:
- unit = "ft";
- break;
- }
- return String.format("In %s %s", distance.getDisplayValue(), unit);
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/NavigationFragment.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/NavigationFragment.java
deleted file mode 100644
index d35ba02..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/NavigationFragment.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.
- */
-package android.car.cluster.sample;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.hardware.display.VirtualDisplay;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.Display;
-import android.view.LayoutInflater;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceHolder.Callback;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import androidx.fragment.app.Fragment;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.lifecycle.ViewModelProviders;
-
-public class NavigationFragment extends Fragment {
- private static final String TAG = "Cluster.NavFragment";
-
- private SurfaceView mSurfaceView;
- private DisplayManager mDisplayManager;
- private Rect mUnobscuredBounds;
- private MainClusterActivity mMainClusterActivity;
- private ClusterViewModel mViewModel;
- private ProgressBar mProgressBar;
- private TextView mMessage;
-
-
- // Static because we want to keep alive this virtual display when navigating through
- // ViewPager (this fragment gets dynamically destroyed and created)
- private static VirtualDisplay mVirtualDisplay;
- private static int mRegisteredNavDisplayId = Display.INVALID_DISPLAY;
- private boolean mNavigationDisplayUpdatePending = false;
-
- public NavigationFragment() {
- // Required empty public constructor
- }
-
-
- private final DisplayListener mDisplayListener = new DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- int navDisplayId = getVirtualDisplayId();
- Log.i(TAG, "onDisplayAdded, displayId: " + displayId
- + ", navigation display id: " + navDisplayId);
-
- if (navDisplayId == displayId) {
- mRegisteredNavDisplayId = displayId;
- updateNavigationDisplay();
- }
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- if (mRegisteredNavDisplayId == displayId) {
- mRegisteredNavDisplayId = Display.INVALID_DISPLAY;
- updateNavigationDisplay();
- }
- }
-
- @Override
- public void onDisplayChanged(int displayId) {}
- };
-
- private void updateNavigationDisplay() {
- if (mMainClusterActivity == null) {
- // Not attached to the activity yet. Let's wait.
- mNavigationDisplayUpdatePending = true;
- return;
- }
-
- mNavigationDisplayUpdatePending = false;
- mMainClusterActivity.updateNavDisplay(new MainClusterActivity.VirtualDisplay(
- mRegisteredNavDisplayId, mUnobscuredBounds));
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- mMainClusterActivity = (MainClusterActivity) context;
- if (mNavigationDisplayUpdatePending) {
- updateNavigationDisplay();
- }
- }
-
- @Override
- public void onDetach() {
- mMainClusterActivity = null;
- super.onDetach();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- Log.i(TAG, "onCreateView");
- ViewModelProvider provider = ViewModelProviders.of(requireActivity());
- mViewModel = provider.get(ClusterViewModel.class);
-
- mDisplayManager = getActivity().getSystemService(DisplayManager.class);
- mDisplayManager.registerDisplayListener(mDisplayListener, new Handler());
-
- // Inflate the layout for this fragment
- View root = inflater.inflate(R.layout.fragment_navigation, container, false);
-
- mSurfaceView = root.findViewById(R.id.nav_surface);
- mSurfaceView.getHolder().addCallback(new Callback() {
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.i(TAG, "surfaceCreated, holder: " + holder);
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Log.i(TAG, "surfaceChanged, holder: " + holder + ", size:" + width + "x" + height
- + ", format:" + format);
-
- // Create dummy unobscured area to report to navigation activity.
- int obscuredWidth = (int) getResources()
- .getDimension(R.dimen.speedometer_overlap_width);
- int obscuredHeight = (int) getResources()
- .getDimension(R.dimen.navigation_gradient_height);
- mUnobscuredBounds = new Rect(
- obscuredWidth, /* left: size of gauge */
- obscuredHeight, /* top: gradient */
- width - obscuredWidth, /* right: size of the display - size of gauge */
- height - obscuredHeight /* bottom: size of display - gradient */
- );
-
- if (mVirtualDisplay == null) {
- mVirtualDisplay = createVirtualDisplay(holder.getSurface(), width, height);
- } else {
- mVirtualDisplay.setSurface(holder.getSurface());
- }
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.i(TAG, "surfaceDestroyed, holder: " + holder + ", detaching surface from"
- + " display, surface: " + holder.getSurface());
- // detaching surface is similar to turning off the display
- mVirtualDisplay.setSurface(null);
- }
- });
- mProgressBar = root.findViewById(R.id.progress_bar);
- mMessage = root.findViewById(R.id.message);
-
- mViewModel.getNavigationActivityState().observe(this, state -> {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "State: " + state);
- }
- mProgressBar.setVisibility(state == ClusterViewModel.NavigationActivityState.LOADING
- ? View.VISIBLE : View.INVISIBLE);
- mMessage.setVisibility(state == ClusterViewModel.NavigationActivityState.NOT_SELECTED
- ? View.VISIBLE : View.INVISIBLE);
- });
-
- return root;
- }
-
- private VirtualDisplay createVirtualDisplay(Surface surface, int width, int height) {
- Log.i(TAG, "createVirtualDisplay, surface: " + surface + ", width: " + width
- + "x" + height);
- return mDisplayManager.createVirtualDisplay("Cluster-App-VD", width, height, 160, surface,
- DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.i(TAG, "onDestroy");
- }
-
- private int getVirtualDisplayId() {
- return (mVirtualDisplay != null && mVirtualDisplay.getDisplay() != null)
- ? mVirtualDisplay.getDisplay().getDisplayId() : Display.INVALID_DISPLAY;
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/NetworkedVirtualDisplay.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/NetworkedVirtualDisplay.java
deleted file mode 100644
index ba64ce5..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/NetworkedVirtualDisplay.java
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.car.cluster.sample;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.hardware.display.VirtualDisplay;
-import android.media.MediaCodec;
-import android.media.MediaCodec.BufferInfo;
-import android.media.MediaCodec.CodecException;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecInfo.CodecProfileLevel;
-import android.media.MediaFormat;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-import android.view.Display;
-import android.view.Surface;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.nio.ByteBuffer;
-import java.util.UUID;
-
-/**
- * This class encapsulates all work related to managing networked virtual display.
- * <p>
- * It opens a socket and listens on port {@code PORT} for connections, or the emulator pipe. Once
- * connection is established it creates virtual display and media encoder and starts streaming video
- * to that socket. If the receiving part is disconnected, it will keep port open and virtual
- * display won't be destroyed.
- */
-public class NetworkedVirtualDisplay {
- private static final String TAG = "Cluster." + NetworkedVirtualDisplay.class.getSimpleName();
-
- private final String mUniqueId = UUID.randomUUID().toString();
-
- private final DisplayManager mDisplayManager;
- private final int mWidth;
- private final int mHeight;
- private final int mDpi;
-
- private static final int FPS = 25;
- private static final int BITRATE = 6144000;
- private static final String MEDIA_FORMAT_MIMETYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
-
- public static final int MSG_START = 0;
- public static final int MSG_STOP = 1;
- public static final int MSG_SEND_FRAME = 2;
-
- private static final String PIPE_NAME = "pipe:qemud:carCluster";
- private static final String PIPE_DEVICE = "/dev/qemu_pipe";
-
- // Constants shared with emulator in car-cluster-widget.cpp
- public static final int PIPE_START = 1;
- public static final int PIPE_STOP = 2;
-
- private static final int PORT = 5151;
-
- private SenderThread mActiveThread;
- private HandlerThread mBroadcastThread = new HandlerThread("BroadcastThread");
-
- private VirtualDisplay mVirtualDisplay;
- private MediaCodec mVideoEncoder;
- private Handler mHandler;
- private byte[] mBuffer = null;
- private int mLastFrameLength = 0;
-
- private final DebugCounter mCounter = new DebugCounter();
-
- NetworkedVirtualDisplay(Context context, int width, int height, int dpi) {
- mDisplayManager = context.getSystemService(DisplayManager.class);
- mWidth = width;
- mHeight = height;
- mDpi = dpi;
-
- DisplayListener displayListener = new DisplayListener() {
- @Override
- public void onDisplayAdded(int i) {
- final Display display = mDisplayManager.getDisplay(i);
- if (display != null && getDisplayName().equals(display.getName())) {
- onVirtualDisplayReady(display);
- }
- }
-
- @Override
- public void onDisplayRemoved(int i) {}
-
- @Override
- public void onDisplayChanged(int i) {}
- };
-
- mDisplayManager.registerDisplayListener(displayListener, new Handler());
- }
-
- /**
- * Opens socket and creates virtual display asynchronously once connection established. Clients
- * of this class may subscribe to
- * {@link android.hardware.display.DisplayManager#registerDisplayListener(
- * DisplayListener, Handler)} to be notified when virtual display is created.
- * Note, that this method should be called only once.
- *
- * @return Unique display name associated with the instance of this class.
- *
- * @see {@link Display#getName()}
- *
- * @throws IllegalStateException thrown if networked display already started
- */
- public String start() {
- if (mBroadcastThread.isAlive()) {
- throw new IllegalStateException("Already started");
- }
-
- mBroadcastThread.start();
- mHandler = new BroadcastThreadHandler(mBroadcastThread.getLooper());
- mHandler.sendMessage(Message.obtain(mHandler, MSG_START));
- return getDisplayName();
- }
-
- public void release() {
- mHandler.sendMessage(Message.obtain(mHandler, MSG_STOP));
- mBroadcastThread.quitSafely();
-
- if (mVirtualDisplay != null) {
- mVirtualDisplay.setSurface(null);
- mVirtualDisplay.release();
- mVirtualDisplay = null;
- }
- }
-
- private String getDisplayName() {
- return "Cluster-" + mUniqueId;
- }
-
- private VirtualDisplay createVirtualDisplay() {
- Log.i(TAG, "createVirtualDisplay " + mWidth + "x" + mHeight +"@" + mDpi);
- return mDisplayManager.createVirtualDisplay(getDisplayName(), mWidth, mHeight, mDpi,
- null, 0 /* flags */, null, null );
- }
-
- private void onVirtualDisplayReady(Display display) {
- Log.i(TAG, "onVirtualDisplayReady, display: " + display);
- }
-
- private void startCasting(Handler handler) {
- Log.i(TAG, "Start casting...");
- if (mVideoEncoder != null) {
- Log.i(TAG, "Already started casting");
- return;
- }
- mVideoEncoder = createVideoStream(handler);
-
- if (mVirtualDisplay == null) {
- mVirtualDisplay = createVirtualDisplay();
- }
-
- mVirtualDisplay.setSurface(mVideoEncoder.createInputSurface());
- mVideoEncoder.start();
- Log.i(TAG, "Video encoder started");
- }
-
- private MediaCodec createVideoStream(Handler handler) {
- MediaCodec encoder;
- try {
- encoder = MediaCodec.createEncoderByType(MEDIA_FORMAT_MIMETYPE);
- } catch (IOException e) {
- Log.e(TAG, "Failed to create video encoder for " + MEDIA_FORMAT_MIMETYPE, e);
- return null;
- }
-
- encoder.setCallback(new MediaCodec.Callback() {
- @Override
- public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
- // Nothing to do
- }
-
- @Override
- public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index,
- @NonNull BufferInfo info) {
- mCounter.outputBuffers++;
- doOutputBufferAvailable(index, info);
- }
-
- @Override
- public void onError(@NonNull MediaCodec codec, @NonNull CodecException e) {
- Log.e(TAG, "onError, codec: " + codec, e);
- mCounter.bufferErrors++;
- stopCasting();
- startCasting(handler);
- }
-
- @Override
- public void onOutputFormatChanged(@NonNull MediaCodec codec,
- @NonNull MediaFormat format) {
- Log.i(TAG, "onOutputFormatChanged, codec: " + codec + ", format: " + format);
-
- }
- }, handler);
-
- configureVideoEncoder(encoder, mWidth, mHeight);
- return encoder;
- }
-
- private void doOutputBufferAvailable(int index, @NonNull BufferInfo info) {
- mHandler.removeMessages(MSG_SEND_FRAME);
-
- ByteBuffer encodedData = mVideoEncoder.getOutputBuffer(index);
- if (encodedData == null) {
- throw new RuntimeException("couldn't fetch buffer at index " + index);
- }
-
- if (info.size != 0) {
- encodedData.position(info.offset);
- encodedData.limit(info.offset + info.size);
- mLastFrameLength = encodedData.remaining();
- if (mBuffer == null || mBuffer.length < mLastFrameLength) {
- Log.i(TAG, "Allocating new buffer: " + mLastFrameLength);
- mBuffer = new byte[mLastFrameLength];
- }
- encodedData.get(mBuffer, 0, mLastFrameLength);
- mVideoEncoder.releaseOutputBuffer(index, false);
-
- // Send this frame asynchronously (avoiding blocking on the socket). We might miss
- // frames if the consumer is not fast enough, but this is acceptable.
- sendFrameAsync(0);
- } else {
- Log.e(TAG, "Skipping empty buffer");
- mVideoEncoder.releaseOutputBuffer(index, false);
- }
- }
-
- private void sendFrameAsync(long delayMs) {
- Message msg = mHandler.obtainMessage(MSG_SEND_FRAME);
- mHandler.sendMessageDelayed(msg, delayMs);
- }
-
- private void sendFrame(byte[] buf, int len) {
- if (mActiveThread != null) {
- mActiveThread.send(buf, len);
- }
- }
-
- private void stopCasting() {
- Log.i(TAG, "Stopping casting...");
-
- if (mVirtualDisplay != null) {
- Surface surface = mVirtualDisplay.getSurface();
- if (surface != null) surface.release();
- }
-
- if (mVideoEncoder != null) {
- // Releasing encoder as stop/start didn't work well (couldn't create or reuse input
- // surface).
- try {
- mVideoEncoder.stop();
- mVideoEncoder.release();
- } catch (IllegalStateException e) {
- // do nothing, already released
- }
- mVideoEncoder = null;
- }
- Log.i(TAG, "Casting stopped");
- }
-
- private class BroadcastThreadHandler extends Handler {
- private static final int MAX_FAIL_COUNT = 10;
- private int mFailConnectCounter;
-
- BroadcastThreadHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_START:
- Log.i(TAG, "Received start message");
-
- // Make sure mActiveThread cannot start multiple times
- if (mActiveThread != null) {
- Log.w(TAG, "Trying to start a running thread. Race condition may exist");
- break;
- }
-
- // Failure to connect to either pipe or network returns null
- if (mActiveThread == null) {
- mActiveThread = tryPipeConnect();
- }
- if (mActiveThread == null) {
- mActiveThread = tryNetworkConnect();
- }
- if (mActiveThread == null) {
- // When failed attempt limit is reached, clean up and quit this thread.
- mFailConnectCounter++;
- if (mFailConnectCounter >= MAX_FAIL_COUNT) {
- Log.e(TAG, "Too many failed connection attempts; aborting");
- release();
- throw new RuntimeException("Abort after failed connection attempts");
- }
- mHandler.sendMessage(Message.obtain(mHandler, MSG_START));
- break;
- }
-
- try {
- mFailConnectCounter = 0;
- mCounter.clientsConnected++;
- mActiveThread.start();
- startCasting(this);
- } catch (Exception e) {
- Log.e(TAG, "Failed to start thread", e);
- Log.e(TAG, "DebugCounter: " + mCounter);
- }
- break;
-
- case MSG_STOP:
- Log.i(TAG, "Received stop message");
- stopCasting();
- mCounter.clientsDisconnected++;
- if (mActiveThread != null) {
- mActiveThread.close();
- try {
- mActiveThread.join();
- } catch (InterruptedException e) {
- Log.e(TAG, "Waiting for active thread to close failed", e);
- }
- mActiveThread = null;
- }
- break;
-
- case MSG_SEND_FRAME:
- if (mActiveThread == null) {
- // Stop the chaining signal if there's no client to send to
- break;
- }
- sendFrame(mBuffer, mLastFrameLength);
- // We will keep sending last frame every second as a heartbeat.
- sendFrameAsync(1000L);
- break;
- }
- }
-
- // Returns null if can't establish pipe connection
- // Otherwise returns the corresponding client thread
- private PipeThread tryPipeConnect() {
- try {
- RandomAccessFile pipe = new RandomAccessFile(PIPE_DEVICE, "rw");
- byte[] temp = new byte[PIPE_NAME.length() + 1];
- temp[PIPE_NAME.length()] = 0;
- System.arraycopy(PIPE_NAME.getBytes(), 0, temp, 0, PIPE_NAME.length());
- pipe.write(temp);
-
- // At this point, the pipe exists, so we will just wait for a start signal
- // This is in case pipe still sends leftover stops from last instantiation
- int signal = pipe.read();
- while (signal != PIPE_START) {
- Log.i(TAG, "Received non-start signal: " + signal);
- signal = pipe.read();
- }
- return new PipeThread(mHandler, pipe);
- } catch (IOException e) {
- Log.e(TAG, "Failed to establish pipe connection", e);
- return null;
- }
- }
-
- // Returns null if can't establish network connection
- // Otherwise returns the corresponding client thread
- private SocketThread tryNetworkConnect() {
- try {
- ServerSocket serverSocket = new ServerSocket(PORT);
- Log.i(TAG, "Server socket opened");
- Socket socket = serverSocket.accept();
- socket.setTcpNoDelay(true);
- socket.setKeepAlive(true);
- socket.setSoLinger(true, 0);
-
- InputStream inputStream = socket.getInputStream();
- OutputStream outputStream = socket.getOutputStream();
-
- return new SocketThread(mHandler, serverSocket, inputStream, outputStream);
- } catch (IOException e) {
- Log.e(TAG, "Failed to establish network connection", e);
- return null;
- }
- }
- }
-
- private static void configureVideoEncoder(MediaCodec codec, int width, int height) {
- MediaFormat format = MediaFormat.createVideoFormat(MEDIA_FORMAT_MIMETYPE, width, height);
-
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
- MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
- format.setInteger(MediaFormat.KEY_BIT_RATE, BITRATE);
- format.setInteger(MediaFormat.KEY_FRAME_RATE, FPS);
- format.setInteger(MediaFormat.KEY_CAPTURE_RATE, FPS);
- format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
- format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1); // 1 second between I-frames
- format.setInteger(MediaFormat.KEY_LEVEL, CodecProfileLevel.AVCLevel31);
- format.setInteger(MediaFormat.KEY_PROFILE,
- MediaCodecInfo.CodecProfileLevel.AVCProfileBaseline);
-
- codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
- }
-
- @Override
- public String toString() {
- return getClass() + "{"
- + ", receiver connected: " + (mActiveThread != null)
- + ", encoder: " + mVideoEncoder
- + ", virtualDisplay" + mVirtualDisplay
- + "}";
- }
-
- private static class DebugCounter {
- long outputBuffers;
- long bufferErrors;
- long clientsConnected;
- long clientsDisconnected;
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "{"
- + "outputBuffers=" + outputBuffers
- + ", bufferErrors=" + bufferErrors
- + ", clientsConnected=" + clientsConnected
- + ", clientsDisconnected= " + clientsDisconnected
- + "}";
- }
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/PhoneFragment.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/PhoneFragment.java
deleted file mode 100644
index c546f9d..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/PhoneFragment.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.os.Bundle;
-import android.telephony.TelephonyManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-import androidx.lifecycle.ViewModelProviders;
-
-import com.android.car.telephony.common.TelecomUtils;
-
-/**
- * Displays ongoing call information.
- */
-public class PhoneFragment extends Fragment {
- private View mUserProfileContainerView;
-
- private PhoneFragmentViewModel mViewModel;
-
- public PhoneFragment() {
- // Required empty public constructor
- }
-
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
- Bundle savedInstanceState) {
- FragmentActivity activity = requireActivity();
- mViewModel = ViewModelProviders.of(activity).get(
- PhoneFragmentViewModel.class);
-
- View fragmentView = inflater.inflate(R.layout.fragment_phone, container, false);
- mUserProfileContainerView = fragmentView.findViewById(R.id.user_profile_container);
-
- TextView body = mUserProfileContainerView.findViewById(R.id.body);
- ImageView avatar = mUserProfileContainerView.findViewById(R.id.avatar);
- TextView nameView = mUserProfileContainerView.findViewById(R.id.title);
-
- mViewModel.getContactInfo().observe(getViewLifecycleOwner(), (contactInfo) -> {
- nameView.setText(contactInfo.getDisplayName());
- TelecomUtils.setContactBitmapAsync(getContext(),
- avatar, contactInfo.getContact(), contactInfo.getNumber());
- });
- mViewModel.getBody().observe(getViewLifecycleOwner(), body::setText);
- mViewModel.getState().observe(getViewLifecycleOwner(), (state) -> {
- if (state == TelephonyManager.CALL_STATE_IDLE) {
- mUserProfileContainerView.setVisibility(View.GONE);
- } else {
- mUserProfileContainerView.setVisibility(View.VISIBLE);
- }
- });
-
- return fragmentView;
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/PhoneFragmentViewModel.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/PhoneFragmentViewModel.java
deleted file mode 100644
index dd955e1..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/PhoneFragmentViewModel.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import static androidx.lifecycle.Transformations.map;
-
-import android.app.Application;
-import android.content.Context;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-
-import com.android.car.telephony.common.Contact;
-import com.android.car.telephony.common.InMemoryPhoneBook;
-import com.android.car.telephony.common.TelecomUtils;
-
-/**
- * View model for {@link PhoneFragment}
- */
-public final class PhoneFragmentViewModel extends AndroidViewModel {
- private MutableLiveData<Long> mConnectTime = new MutableLiveData<>();
- private MutableLiveData<Integer> mState = new MutableLiveData<>();
- private MutableLiveData<String> mNumber = new MutableLiveData<>();
- private LiveData<String> mBody;
- private LiveData<ContactInfo> mContactInfo;
-
- private PhoneStateCallback mCallback;
-
- public PhoneFragmentViewModel(Application application) {
- super(application);
-
- TelephonyManager telephonyManager = (TelephonyManager) application.getSystemService(
- Context.TELEPHONY_SERVICE);
- telephonyManager.listen(new ClusterPhoneStateListener(),
- PhoneStateListener.LISTEN_CALL_STATE);
-
- mBody = new SelfRefreshDescriptionLiveData(getApplication(), mState, mNumber, mConnectTime);
-
- mContactInfo = map(mNumber, (number) -> {
- return new ContactInfo(number);
- });
- }
-
- public interface PhoneStateCallback {
- void onCall();
-
- void onDisconnect();
- }
-
- public LiveData<Integer> getState() {
- return mState;
- }
-
- public LiveData<String> getBody() {
- return mBody;
- }
-
- public LiveData<ContactInfo> getContactInfo() {
- return mContactInfo;
- }
-
- public void setPhoneStateCallback(PhoneStateCallback callback) {
- mCallback = callback;
- }
-
- /**
- * Listens to phone state changes
- */
- private class ClusterPhoneStateListener extends PhoneStateListener {
- ClusterPhoneStateListener() {
- }
-
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- super.onCallStateChanged(state, incomingNumber);
-
- mState.setValue(state);
- mNumber.setValue(incomingNumber);
-
- if (state == TelephonyManager.CALL_STATE_IDLE) {
- if (mCallback != null) {
- mCallback.onDisconnect();
- }
- } else if (state == TelephonyManager.CALL_STATE_RINGING) {
- if (mCallback != null) {
- mCallback.onCall();
- }
- } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
- mConnectTime.setValue(System.currentTimeMillis());
- if (mCallback != null) {
- mCallback.onCall();
- }
- }
- }
- }
-
- public class ContactInfo {
- private String mNumber;
- private String mDisplayName;
- private Contact mContact;
-
- public ContactInfo(String number) {
- mNumber = number;
- mDisplayName = TelecomUtils.getDisplayNameAndAvatarUri(getApplication(), number).first;
- mContact = InMemoryPhoneBook.get().lookupContactEntry(number);
- }
-
- public String getNumber() {
- return mNumber;
- }
-
- public String getDisplayName() {
- return mDisplayName;
- }
-
- public Contact getContact() {
- return mContact;
- }
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/PipeThread.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/PipeThread.java
deleted file mode 100644
index c96f482..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/PipeThread.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-import android.os.Handler;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * Thread that can send data to the emulator using a qemud service.
- */
-public class PipeThread extends SenderThread {
- private static final String TAG = "Cluster." + PipeThread.class.getSimpleName();
-
- private RandomAccessFile mPipe;
-
- /**
- * Creates instance of pipe thread that can write to given pipe file.
- *
- * @param handler {@link Handler} used to message broadcaster.
- * @param pipe {@link RandomAccessFile} file already connected to pipe.
- */
- PipeThread(Handler handler, RandomAccessFile pipe) {
- super(handler);
- mPipe = pipe;
- }
-
- public void run() {
- try {
- int signal = mPipe.read();
- while (signal != NetworkedVirtualDisplay.PIPE_STOP) {
- Log.i(TAG, "Received non-stop signal: " + signal);
- signal = mPipe.read();
- }
- restart();
- } catch (IOException e) {
- Log.e(TAG, "Failed to read from pipe");
- restart();
- }
- }
-
- @Override
- public void send(byte[] buf, int len) {
- try {
- // First sends the size prior to sending the data, since receiving side only sees
- // the size of the buffer, which could be significant larger than the actual data.
- mPipe.write(ByteBuffer.allocate(4)
- .order(ByteOrder.LITTLE_ENDIAN).putInt(len).array());
- mPipe.write(buf);
- } catch (IOException e) {
- Log.e(TAG, "Write to pipe failed");
- restart();
- }
- }
-
- @Override
- public void close() {
- try {
- mPipe.close();
- } catch (IOException e) {
- Log.e(TAG, "Failed to close pipe", e);
- }
- }
-}
-
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/SelfRefreshDescriptionLiveData.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/SelfRefreshDescriptionLiveData.java
deleted file mode 100644
index 79122c4..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/SelfRefreshDescriptionLiveData.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import android.content.Context;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MediatorLiveData;
-
-import com.android.car.telephony.common.TelecomUtils;
-
-/**
- * Emits the description for the body in {@link PhoneFragmentViewModel}.
- *
- * This description may be the current duration of the call, call state, call type,
- * or a combination of them.
- *
- * Possible strings:
- * "Ringing"
- * "1:05"
- * "Mobile · Dialing"
- * "Mobile · 1:05"
- */
-public class SelfRefreshDescriptionLiveData extends MediatorLiveData<String> {
- private final LiveData<Long> mConnectTimeLiveData;
- private final LiveData<String> mNumberLiveData;
- private final LiveData<Integer> mStateLiveData;
- private final Context mContext;
-
- /**
- * @param stateLiveData LiveData holding the {@link TelephonyManager} call state
- * @param numberLiveData LiveData holding the call number
- * @param connectTimeLiveData LiveData holding the starting timestamp of the call
- */
- public SelfRefreshDescriptionLiveData(Context context,
- LiveData<Integer> stateLiveData,
- LiveData<String> numberLiveData,
- LiveData<Long> connectTimeLiveData) {
- mContext = context;
- mNumberLiveData = numberLiveData;
- mStateLiveData = stateLiveData;
- mConnectTimeLiveData = connectTimeLiveData;
-
- HeartBeatLiveData heartBeatLiveData = new HeartBeatLiveData(DateUtils.SECOND_IN_MILLIS);
-
- addSource(stateLiveData, (trigger) -> updateDescription());
- addSource(heartBeatLiveData, (trigger) -> updateDescription());
- addSource(mNumberLiveData, (trigger) -> updateDescription());
- addSource(mConnectTimeLiveData, (trigger) -> updateDescription());
- }
-
- private void updateDescription() {
- String number = mNumberLiveData.getValue();
- Integer callState = mStateLiveData.getValue();
- Long connectTime = mConnectTimeLiveData.getValue();
- if (callState != null) {
- String newDescription = getCallInfoText(mContext, callState, number,
- connectTime != null ? connectTime : 0);
-
- String oldDescription = getValue();
- if (!newDescription.equals(oldDescription)) {
- setValue(newDescription);
- }
- } else {
- setValue("");
- }
- }
-
- /**
- * @return A formatted string that has information about the phone call
- * Possible strings:
- * "Mobile · Dialing"
- * "Mobile · 1:05"
- */
- private String getCallInfoText(Context context, Integer callState, String number,
- Long connectTime) {
- CharSequence label = TelecomUtils.getTypeFromNumber(context, number);
- String text = "";
- if (callState == TelephonyManager.CALL_STATE_OFFHOOK) {
- long duration = connectTime > 0 ? System.currentTimeMillis()
- - connectTime : 0;
- String durationString = DateUtils.formatElapsedTime(duration / 1000);
- if (!TextUtils.isEmpty(durationString) && !TextUtils.isEmpty(label)) {
- text = context.getString(R.string.phone_label_with_info, label,
- durationString);
- } else if (!TextUtils.isEmpty(durationString)) {
- text = durationString;
- } else if (!TextUtils.isEmpty(label)) {
- text = (String) label;
- }
- } else {
- String state = callStateToUiString(context, callState);
- if (!TextUtils.isEmpty(label)) {
- text = context.getString(R.string.phone_label_with_info, label, state);
- } else {
- text = state;
- }
- }
-
- return text;
- }
-
- /**
- * @return A string representation of the call state that can be presented to a user.
- */
- private String callStateToUiString(Context context, int state) {
- switch (state) {
- case TelephonyManager.CALL_STATE_IDLE:
- return context.getString(R.string.call_state_call_ended);
- case TelephonyManager.CALL_STATE_RINGING:
- return context.getString(R.string.call_state_call_ringing);
- case TelephonyManager.CALL_STATE_OFFHOOK:
- return context.getString(R.string.call_state_call_active);
- default:
- return "";
- }
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/SenderThread.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/SenderThread.java
deleted file mode 100644
index 9def7ee..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/SenderThread.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-/**
- * This class serves as a template for sending to specific clients of the broadcaster.
- */
-public abstract class SenderThread extends Thread {
- private static final String TAG = "Cluster.SenderThread";
-
- private Handler mHandler;
-
- SenderThread(Handler handler) {
- mHandler = handler;
- }
-
- abstract void send(byte[] buf, int len);
- abstract void close();
-
- /**
- * Tells the broadcasting thread to stop and close everything in progress, and start over again.
- * It will kill the current instance of this thread, and produce a new one.
- */
- synchronized void restart() {
- if (mHandler.hasMessages(NetworkedVirtualDisplay.MSG_START)) return;
- Log.i(TAG, "Sending STOP and START msgs to NetworkedVirtualDisplay");
-
- mHandler.sendMessage(Message.obtain(mHandler, NetworkedVirtualDisplay.MSG_STOP));
- mHandler.sendMessage(Message.obtain(mHandler, NetworkedVirtualDisplay.MSG_START));
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/SocketThread.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/SocketThread.java
deleted file mode 100644
index a5215b0..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/SocketThread.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-import android.os.Handler;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.ServerSocket;
-
-/**
- * The thread that will send data on an opened socket.
- */
-public class SocketThread extends SenderThread {
- private static final String TAG = "Cluster." + SocketThread.class.getSimpleName();
- private ServerSocket mServerSocket;
- private OutputStream mOutputStream;
- private InputStream mInputStream;
-
- /**
- * Create instance of thread that can write to given open socket.
- *
- * @param handler {@link Handler} used to message the broadcaster.
- * @param serverSocket {@link ServerSocket} should be already opened.
- * @param inputStream {@link InputStream} corresponding to opened socket.
- * @param outputStream {@link OutputStream} corresponding to opened socket.
- */
- SocketThread(Handler handler, ServerSocket serverSocket, InputStream inputStream,
- OutputStream outputStream) {
- super(handler);
- mServerSocket = serverSocket;
- mInputStream = inputStream;
- mOutputStream = outputStream;
- }
-
- public void run() {
- try {
- // This read should block until something disconnects (or something
- // similar) which should cause an exception, in which case we should
- // try to setup again and reconnect
- mInputStream.read();
- } catch (IOException e) {
- Log.e(TAG, "Socket thread disconnected.");
- }
- restart();
- }
-
- @Override
- public void send(byte[] buf, int len) {
- try {
- mOutputStream.write(buf, 0, len);
- } catch (IOException e) {
- Log.e(TAG, "Failed to write data to socket, retrying connection");
- restart();
- }
- }
-
- @Override
- public void close() {
- if (mServerSocket != null) {
- try {
- mServerSocket.close();
- } catch (IOException e) {
- Log.w(TAG, "Failed to close server socket, ignoring");
- }
- mServerSocket = null;
- }
- mInputStream = null;
- mOutputStream = null;
- }
-}
-
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/sensors/Sensor.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/sensors/Sensor.java
deleted file mode 100644
index 8f01cd7..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/sensors/Sensor.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample.sensors;
-
-import android.car.VehiclePropertyType;
-import android.car.hardware.CarPropertyValue;
-
-import java.util.function.Function;
-
-/**
- * Description of a car sensor. It can be used as identifier at
- * {@link android.car.cluster.sample.ClusterViewModel#getSensor(Sensor)} to obtain a
- * {@link androidx.lifecycle.LiveData} to track values of this sensor. The sensor description is
- * used to process and decode the information reported by the car.
- * <p>
- * All instances of this class must be obtained from {@link Sensors}.
- *
- * @param <T> data type used by this sensor.
- */
-public class Sensor<T> {
- /** Name of the sensor (for debugging) */
- public final String mName;
- /** VHAL identifier of this sensor */
- public final int mPropertyId;
- /** VHAL area associated with this sensor (each area is reported as an independent sensor) */
- public final int mAreaId;
- /**
- * Data type expected to be reported by the VHAL. If the values received don't match with the
- * expected ones, we warn about it and ignore the value.
- */
- @VehiclePropertyType.Enum
- public final int mExpectedPropertyType;
- /** VHAL Area associated with this sensor. */
- public final Function<CarPropertyValue<?>, T> mAdapter;
-
- /**
- * Creates a new sensor. Only {@link Sensors} should use this constructor.
- */
- Sensor(String name, int propertyId, int areaId, int expectedPropertyType,
- Function<CarPropertyValue<?>, T> adapter) {
- mName = name;
- mPropertyId = propertyId;
- mAreaId = areaId;
- mExpectedPropertyType = expectedPropertyType;
- mAdapter = adapter;
- }
-
- @Override
- public String toString() {
- return mName;
- }
-}
diff --git a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/sensors/Sensors.java b/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/sensors/Sensors.java
deleted file mode 100644
index 90d6350..0000000
--- a/tests/DirectRenderingClusterSample/src/android/car/cluster/sample/sensors/Sensors.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample.sensors;
-
-import android.car.VehiclePropertyIds;
-import android.car.VehiclePropertyType;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.CarSensorEvent;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-
-/**
- * The collection of all sensors supported by this application.
- */
-public class Sensors {
- /** Area identifier used for sensors corresponding to global VHAL properties */
- public static final int GLOBAL_AREA_ID = -1;
-
- private static Sensors sInstance;
- private static List<Sensor<?>> sSensors = new ArrayList<>();
- private Map<Integer, List<Sensor<?>>> mSensorsByPropertyId = new HashMap<>();
-
- /** Possible values of the {@link #SENSOR_GEAR} sensor */
- public enum Gear {
- NEUTRAL,
- REVERSE,
- DRIVE,
- PARK,
- }
-
- /** Fuel of the car, measured in millimeters */
- public static final Sensor<Float> SENSOR_FUEL = registerSensor(
- "Fuel", VehiclePropertyIds.FUEL_LEVEL, GLOBAL_AREA_ID, VehiclePropertyType.FLOAT,
- value -> (Float) value.getValue());
- /** Fuel capacity of the car, measured in millimeters */
- public static final Sensor<Float> SENSOR_FUEL_CAPACITY = registerSensor(
- "Fuel Capacity", VehiclePropertyIds.INFO_FUEL_CAPACITY, GLOBAL_AREA_ID,
- VehiclePropertyType.FLOAT,
- value -> (Float) value.getValue());
- /** RPMs */
- public static final Sensor<Float> SENSOR_RPM = registerSensor(
- "RPM", VehiclePropertyIds.ENGINE_RPM, GLOBAL_AREA_ID,
- VehiclePropertyType.FLOAT,
- value -> (Float) value.getValue());
- /** Fuel range in meters */
- public static final Sensor<Float> SENSOR_FUEL_RANGE = registerSensor(
- "Fuel Range", VehiclePropertyIds.RANGE_REMAINING, GLOBAL_AREA_ID,
- VehiclePropertyType.FLOAT,
- value -> (Float) value.getValue());
- /** Speed in meters per second */
- public static final Sensor<Float> SENSOR_SPEED = registerSensor(
- "Speed", VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID,
- VehiclePropertyType.FLOAT,
- value -> (Float) value.getValue());
- /** Current gear of the car */
- public static final Sensor<Gear> SENSOR_GEAR = registerSensor(
- "Gear", VehiclePropertyIds.GEAR_SELECTION, GLOBAL_AREA_ID, VehiclePropertyType.INT32,
- value -> {
- if (value == null) {
- return null;
- }
- Integer gear = (Integer) value.getValue();
- if ((gear & CarSensorEvent.GEAR_REVERSE) != 0) {
- return Gear.REVERSE;
- } else if ((gear & CarSensorEvent.GEAR_NEUTRAL) != 0) {
- return Gear.NEUTRAL;
- } else if ((gear & CarSensorEvent.GEAR_DRIVE) != 0) {
- return Gear.DRIVE;
- } else if ((gear & CarSensorEvent.GEAR_PARK) != 0) {
- return Gear.PARK;
- } else {
- return null;
- }
- });
-
- private static <T> Sensor<T> registerSensor(String propertyName, int propertyId, int areaId,
- int expectedPropertyType, Function<CarPropertyValue<?>, T> adapter) {
- Sensor<T> sensor = new Sensor<>(propertyName, propertyId, areaId, expectedPropertyType,
- adapter);
- sSensors.add(sensor);
- return sensor;
- }
-
- /**
- * Obtains the singleton instance of this class
- */
- public static Sensors getInstance() {
- if (sInstance == null) {
- sInstance = new Sensors();
- }
- return sInstance;
- }
-
- private Sensors() {
- initializeSensorsMap();
- }
-
- private void initializeSensorsMap() {
- for (Sensor<?> sensorId : getSensors()) {
- mSensorsByPropertyId
- .computeIfAbsent(sensorId.mPropertyId, (id) -> new ArrayList<>())
- .add(sensorId);
- }
- }
-
- /**
- * Returns all sensors.
- */
- public List<Sensor<?>> getSensors() {
- return sSensors;
- }
-
- /**
- * Returns all sensors associated to the given VHAL property id.
- */
- public List<Sensor<?>> getSensorsForPropertyId(int propertyId) {
- return mSensorsByPropertyId.get(propertyId);
- }
-
- /**
- * Returns all property ids we care about.
- */
- public Set<Integer> getPropertyIds() {
- return mSensorsByPropertyId.keySet();
- }
-}
diff --git a/tests/DirectRenderingClusterSample/tests/robotests/Android.mk b/tests/DirectRenderingClusterSample/tests/robotests/Android.mk
deleted file mode 100644
index 4dd6b7a..0000000
--- a/tests/DirectRenderingClusterSample/tests/robotests/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-#############################################
-# Messenger Robolectric test target. #
-#############################################
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := DirectRenderingClusterSampleTests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res
-
-LOCAL_JAVA_LIBRARIES := \
- robolectric_android-all-stub \
- Robolectric_all-target \
- mockito-robolectric-prebuilt \
- truth-prebuilt
-
-LOCAL_INSTRUMENTATION_FOR := DirectRenderingClusterSample
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-#############################################################
-# Messenger runner target to run the previous target. #
-#############################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := RunDirectRenderingClusterSampleTests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- DirectRenderingClusterSampleTests
-
-LOCAL_TEST_PACKAGE := DirectRenderingClusterSample
-
-LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))../src
-
-include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
-
-
-
-
diff --git a/tests/DirectRenderingClusterSample/tests/robotests/AndroidManifest.xml b/tests/DirectRenderingClusterSample/tests/robotests/AndroidManifest.xml
deleted file mode 100644
index ad22fc2..0000000
--- a/tests/DirectRenderingClusterSample/tests/robotests/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.car.cluster.sample.robotests">
- <application/>
-
-</manifest>
diff --git a/tests/DirectRenderingClusterSample/tests/robotests/readme.md b/tests/DirectRenderingClusterSample/tests/robotests/readme.md
deleted file mode 100644
index 97cff08..0000000
--- a/tests/DirectRenderingClusterSample/tests/robotests/readme.md
+++ /dev/null
@@ -1,6 +0,0 @@
-Unit test suite for RenderingClusterSample using Robolectric.
-
-```
-$ croot
-$ make RunDirectRenderingClusterSampleTests -j96
-```
\ No newline at end of file
diff --git a/tests/DirectRenderingClusterSample/tests/robotests/src/android/car/cluster/sample/ImageResolverTest.java b/tests/DirectRenderingClusterSample/tests/robotests/src/android/car/cluster/sample/ImageResolverTest.java
deleted file mode 100644
index 0d1cece..0000000
--- a/tests/DirectRenderingClusterSample/tests/robotests/src/android/car/cluster/sample/ImageResolverTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.sample;
-
-import static org.junit.Assert.assertEquals;
-
-import android.graphics.Point;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.internal.DoNotInstrument;
-
-@RunWith(RobolectricTestRunner.class)
-@DoNotInstrument
-public class ImageResolverTest {
- private ImageResolver mImageResolver;
-
- @Before
- public void setup() {
- mImageResolver = new ImageResolver((uri) -> null);
- }
-
- @Test
- public void adjustedSize_widerImageInSquareBox() {
- assertEquals(new Point(20, 10), mImageResolver.getAdjustedSize(40, 20, 20, 20));
- }
-
- @Test
- public void adjustedSize_tallerImageInSquareBox() {
- assertEquals(new Point(10, 20), mImageResolver.getAdjustedSize(20, 40, 20, 20));
- }
-
- @Test
- public void adjustedSize_narrowerImageInSquareBox() {
- assertEquals(new Point(10, 20), mImageResolver.getAdjustedSize(5, 10, 20, 20));
- }
-
- @Test
- public void adjustedSize_shorterImageInSquareBox() {
- assertEquals(new Point(20, 8), mImageResolver.getAdjustedSize(5, 2, 20, 20));
- }
-
- @Test
- public void adjustedSize_widerImageInTallRectangle() {
- assertEquals(new Point(20, 10), mImageResolver.getAdjustedSize(40, 20, 20, 40));
- }
-
- @Test
- public void adjustedSize_tallerImageInTallRectangle() {
- assertEquals(new Point(20, 40), mImageResolver.getAdjustedSize(5, 10, 20, 40));
- }
-
- @Test
- public void adjustedSize_widerImageInWideRectangle() {
- assertEquals(new Point(40, 20), mImageResolver.getAdjustedSize(10, 5, 40, 20));
- }
-
- @Test
- public void adjustedSize_tallerImageInWideRectangle() {
- assertEquals(new Point(10, 20), mImageResolver.getAdjustedSize(5, 10, 40, 20));
- }
-
- @Test
- public void adjustedSize_nullIfNoOriginalWidth() {
- assertEquals(null, mImageResolver.getAdjustedSize(0, 10, 40, 20));
- }
-
- @Test
- public void adjustedSize_nullIfNoOriginalHeight() {
- assertEquals(null, mImageResolver.getAdjustedSize(5, 0, 40, 20));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void adjustedSize_exceptionIfRequestedWidthAndHeightNoProvided() {
- assertEquals(null, mImageResolver.getAdjustedSize(5, 10, 0, 0));
- }
-
- @Test
- public void adjustedSize_flexibleWidth() {
- assertEquals(new Point(20, 30), mImageResolver.getAdjustedSize(40, 60, 0, 30));
- }
-
- @Test
- public void adjustedSize_flexibleHeight() {
- assertEquals(new Point(20, 20), mImageResolver.getAdjustedSize(40, 40, 20, 0));
- }
-}
diff --git a/tests/EmbeddedKitchenSinkApp/Android.mk b/tests/EmbeddedKitchenSinkApp/Android.mk
index 65de56e..386044c 100644
--- a/tests/EmbeddedKitchenSinkApp/Android.mk
+++ b/tests/EmbeddedKitchenSinkApp/Android.mk
@@ -49,6 +49,7 @@
android.hardware.automotive.vehicle-V2.0-java \
vehicle-hal-support-lib \
com.android.car.keventreader-client \
+ guava \
kitchensink-gson
LOCAL_JAVA_LIBRARIES += android.car
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml b/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml
index b918058..a7ff363 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml
@@ -32,6 +32,22 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_weight="1" >
+ <TextView
+ android:id="@+id/zone_selection_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/select_zone" />
+ <Spinner
+ android:id="@+id/zone_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dp"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1" >
<LinearLayout
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/connectivity_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/connectivity_fragment.xml
index dc2d01a..c6e75fe 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/connectivity_fragment.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/connectivity_fragment.xml
@@ -179,4 +179,39 @@
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp">
+ <Button android:id="@+id/networkEnableWifiIntent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Enable Wifi Intent"/>
+ <Button android:id="@+id/networkDisableWifiIntent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Disable Wifi Intent"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp">
+ <Button android:id="@+id/networkEnableBluetoothIntent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Enable Bluetooth Intent"/>
+ <Button android:id="@+id/networkDisableBluetoothIntent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Disable Bluetooth Intent"/>
+ <Button android:id="@+id/networkDiscoverableBluetoothIntent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Discoverable Bluetooth Intent"/>
+ </LinearLayout>
+
</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/projection_status.xml b/tests/EmbeddedKitchenSinkApp/res/layout/projection_status.xml
new file mode 100644
index 0000000..65ccbe8
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/projection_status.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Current Projection State: "/>
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Inactive"
+ android:id="@+id/current_projection_status"/>
+ </LinearLayout>
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Current Projection Package: "/>
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Unknown"
+ android:id="@+id/current_projection_package"/>
+ </LinearLayout>
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Current Projection Details: "/>
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/current_projection_details"/>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/projection_status_details.xml b/tests/EmbeddedKitchenSinkApp/res/layout/projection_status_details.xml
new file mode 100644
index 0000000..ec06152
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/projection_status_details.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Package: "/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:id="@+id/projection_detail_package"/>
+ </LinearLayout>
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Projection State: "/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:id="@+id/projection_detail_state"/>
+ </LinearLayout>
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Transport: "/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:id="@+id/projection_detail_transport"/>
+ </LinearLayout>
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Devices: "/>
+ <LinearLayout android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/projection_detail_devices"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/projection_status_device.xml b/tests/EmbeddedKitchenSinkApp/res/layout/projection_status_device.xml
new file mode 100644
index 0000000..ae4d7a9
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/projection_status_device.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="ID: "/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:id="@+id/projection_device_id"/>
+ </LinearLayout>
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Name: "/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:id="@+id/projection_device_name"/>
+ </LinearLayout>
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Transports: "/>
+ <LinearLayout android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/projection_device_transports"/>
+ </LinearLayout>
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Projecting: "/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:id="@+id/projection_device_projecting"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml b/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml
index 245b945..6c4d945 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml
@@ -13,52 +13,67 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
android:layout_height="match_parent"
- android:orientation="vertical" >
+ android:orientation="vertical">
<!-- Top area -->
<LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/location_layout"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:layout_centerHorizontal="true">
<TextView
android:id="@+id/location_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/location_title" />
+ android:text="@string/location_title"
+ android:textStyle="bold"/>
<TextView
android:id="@+id/location_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:scrollbars="vertical"/>
+ android:scrollbars="vertical"
+ android:textStyle="bold"/>
<TextView
android:id="@+id/accel_info"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:textStyle="bold"/>
<TextView
android:id="@+id/gyro_info"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:textStyle="bold"/>
<TextView
android:id="@+id/mag_info"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:textStyle="bold"/>
</LinearLayout>
+
<!-- Bottom area -->
<LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/sensor_layout"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@+id/location_layout"
+ android:layout_alignStart="@+id/location_layout">
<TextView
android:id="@+id/sensor_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/sensor_title" />
+ android:text="@string/sensor_title"
+ android:textStyle="bold"/>
<TextView
android:id="@+id/sensor_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:scrollbars="vertical"/>
+ android:scrollbars="vertical"
+ android:textStyle="bold"/>
</LinearLayout>
-</LinearLayout>
+
+</RelativeLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 77b64c7..d1ce0d3 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -131,6 +131,8 @@
<string name="microphone_off" translatable="false">Mic Off</string>
<string name="mock_audio_on" translatable="false">Audio Mocking On</string>
<string name="mock_audio_off" translatable="false">Audio Mocking Off</string>
+ <string name="select_zone" translatable="false">Select Zone</string>
+
<!-- keyboard test fragment -->
<string name="keyboard_test_title" translatable="false">Keyboard Test</string>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index a80c3b4..70949a9 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -18,6 +18,7 @@
import android.car.Car;
import android.car.CarAppFocusManager;
+import android.car.CarProjectionManager;
import android.car.hardware.CarSensorManager;
import android.car.hardware.hvac.CarHvacManager;
import android.car.hardware.power.CarPowerManager;
@@ -60,6 +61,7 @@
import com.google.android.car.kitchensink.notification.NotificationFragment;
import com.google.android.car.kitchensink.orientation.OrientationTestFragment;
import com.google.android.car.kitchensink.power.PowerTestFragment;
+import com.google.android.car.kitchensink.projection.ProjectionFragment;
import com.google.android.car.kitchensink.property.PropertyTestFragment;
import com.google.android.car.kitchensink.sensor.SensorsTestFragment;
import com.google.android.car.kitchensink.storagelifetime.StorageLifetimeFragment;
@@ -172,6 +174,7 @@
new FragmentMenuEntry("notification", NotificationFragment.class),
new FragmentMenuEntry("orientation test", OrientationTestFragment.class),
new FragmentMenuEntry("power test", PowerTestFragment.class),
+ new FragmentMenuEntry("projection", ProjectionFragment.class),
new FragmentMenuEntry("property test", PropertyTestFragment.class),
new FragmentMenuEntry("sensors", SensorsTestFragment.class),
new FragmentMenuEntry("storage lifetime", StorageLifetimeFragment.class),
@@ -189,6 +192,7 @@
private CarPropertyManager mPropertyManager;
private CarSensorManager mSensorManager;
private CarAppFocusManager mCarAppFocusManager;
+ private CarProjectionManager mCarProjectionManager;
private Object mPropertyManagerReady = new Object();
public CarHvacManager getHvacManager() {
@@ -207,6 +211,10 @@
return mSensorManager;
}
+ public CarProjectionManager getProjectionManager() {
+ return mCarProjectionManager;
+ }
+
/* Open any tab directly:
* adb shell am force-stop com.google.android.car.kitchensink
* adb shell am start -n com.google.android.car.kitchensink/.KitchenSinkActivity \
@@ -322,6 +330,8 @@
android.car.Car.SENSOR_SERVICE);
mCarAppFocusManager =
(CarAppFocusManager) mCarApi.getCarManager(Car.APP_FOCUS_SERVICE);
+ mCarProjectionManager =
+ (CarProjectionManager) mCarApi.getCarManager(Car.PROJECTION_SERVICE);
mPropertyManagerReady.notifyAll();
}
}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
index cf74468..aa889b4 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
@@ -20,9 +20,12 @@
import android.car.CarAppFocusManager;
import android.car.CarAppFocusManager.OnAppFocusChangedListener;
import android.car.CarAppFocusManager.OnAppFocusOwnershipCallback;
+import android.car.media.CarAudioManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.media.AudioAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioFocusRequest;
@@ -36,8 +39,11 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.RadioGroup;
+import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
@@ -47,6 +53,8 @@
import com.google.android.car.kitchensink.CarEmulator;
import com.google.android.car.kitchensink.R;
+import java.util.Arrays;
+
public class AudioTestFragment extends Fragment {
private static final String TAG = "CAR.AUDIO.KS";
private static final boolean DBG = true;
@@ -75,6 +83,10 @@
private AudioAttributes mRadioAudioAttrib;
private AudioAttributes mSystemSoundAudioAttrib;
private CarEmulator mCarEmulator;
+ private CarAudioManager mCarAudioManager;
+ private Spinner mZoneSpinner;
+ ArrayAdapter<Integer> mZoneAdapter;
+ private int mOldZonePosition;
private final AudioManager.OnAudioFocusChangeListener mNavFocusListener = (focusChange) -> {
Log.i(TAG, "Nav focus change:" + focusChange);
@@ -113,6 +125,19 @@
CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
mAppFocusManager.addFocusListener(listener,
CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+
+ mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
+
+ //take care of zone selection
+ int[] zoneList = mCarAudioManager.getAudioZoneIds();
+ Integer[] zoneArray = Arrays.stream(zoneList).boxed().toArray(Integer[]::new);
+ mZoneAdapter = new ArrayAdapter<>(mContext,
+ android.R.layout.simple_spinner_item, zoneArray);
+ mZoneAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mZoneSpinner.setAdapter(mZoneAdapter);
+ mZoneSpinner.setEnabled(true);
+
+
}
@Override
public void onServiceDisconnected(ComponentName name) {
@@ -283,9 +308,46 @@
mCarEmulator = null;
}
});
+
+ //Zone Spinner
+ mZoneSpinner = view.findViewById(R.id.zone_spinner);
+ mZoneSpinner.setEnabled(false);
+ mZoneSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+ handleZoneSelection();
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
return view;
}
+ public void handleZoneSelection() {
+ int position = mZoneSpinner.getSelectedItemPosition();
+ int zone = mZoneAdapter.getItem(position);
+ Log.d(TAG, "Zone Selected: " + zone);
+ try {
+ ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
+ mContext.getPackageName(), 0);
+ int uid = info.uid;
+ Log.d(TAG, "handleZoneSelection App uid: " + uid);
+ if (mCarAudioManager.setZoneIdForUid(zone, uid)) {
+ Log.d(TAG, "Changed uid " + uid + " sound to zone " + zone);
+ mOldZonePosition = position;
+ } else {
+ Log.d(TAG, "Filed to changed uid " + uid + " sound to zone " + zone);
+ mZoneSpinner.setSelection(mOldZonePosition);
+ }
+
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "handleZoneSelection Failed to find name: " , e);
+ }
+ }
+
@Override
public void onDestroyView() {
super.onDestroyView();
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java
index 31b83cc..3bdfd22 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java
@@ -18,7 +18,9 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothAdapter;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Color;
import android.location.LocationManager;
import android.net.ConnectivityManager;
@@ -491,9 +493,49 @@
mTetheringStatusPolled = (TextView) view.findViewById(R.id.tetheringStatusPolled);
mLocalOnlyStatus = (TextView) view.findViewById(R.id.localOnlyStatus);
+ view.findViewById(R.id.networkEnableWifiIntent).setOnClickListener(v -> enableWifiIntent());
+ view.findViewById(R.id.networkDisableWifiIntent)
+ .setOnClickListener(v -> disableWifiIntent());
+ view.findViewById(R.id.networkEnableBluetoothIntent)
+ .setOnClickListener(v -> enableBluetoothIntent());
+ view.findViewById(R.id.networkDisableBluetoothIntent)
+ .setOnClickListener(v -> disableBluetoothIntent());
+ view.findViewById(R.id.networkDiscoverableBluetoothIntent)
+ .setOnClickListener(v -> discoverableBluetoothIntent());
+
return view;
}
+ private void enableWifiIntent() {
+ Intent enableWifi = new Intent(WifiManager.ACTION_REQUEST_ENABLE);
+ enableWifi.putExtra(Intent.EXTRA_PACKAGE_NAME, getContext().getPackageName());
+ startActivity(enableWifi);
+ }
+
+ private void disableWifiIntent() {
+ Intent disableWifi = new Intent(WifiManager.ACTION_REQUEST_DISABLE);
+ disableWifi.putExtra(Intent.EXTRA_PACKAGE_NAME, getContext().getPackageName());
+ startActivity(disableWifi);
+ }
+
+ private void enableBluetoothIntent() {
+ Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ enableBluetooth.putExtra(Intent.EXTRA_PACKAGE_NAME, getContext().getPackageName());
+ startActivity(enableBluetooth);
+ }
+
+ private void disableBluetoothIntent() {
+ Intent disableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_DISABLE);
+ disableBluetooth.putExtra(Intent.EXTRA_PACKAGE_NAME, getContext().getPackageName());
+ startActivity(disableBluetooth);
+ }
+
+ private void discoverableBluetoothIntent() {
+ Intent discoverableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
+ discoverableBluetooth.putExtra(Intent.EXTRA_PACKAGE_NAME, getContext().getPackageName());
+ startActivity(discoverableBluetooth);
+ }
+
@Override
public void onResume() {
super.onResume();
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/projection/ProjectionFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/projection/ProjectionFragment.java
new file mode 100644
index 0000000..66fc1e2
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/projection/ProjectionFragment.java
@@ -0,0 +1,151 @@
+/*
+ * 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.google.android.car.kitchensink.projection;
+
+import android.car.CarProjectionManager;
+import android.car.CarProjectionManager.ProjectionStatusListener;
+import android.car.projection.ProjectionStatus;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.KitchenSinkActivity;
+import com.google.android.car.kitchensink.R;
+import com.google.common.collect.ImmutableMap;
+
+import java.util.List;
+
+/**
+ * Reports information about the current projection status.
+ */
+public class ProjectionFragment extends Fragment {
+ private KitchenSinkActivity mActivity;
+ private CarProjectionManager mCarProjectionManager;
+
+ private TextView mCurrentProjectionStatus;
+ private TextView mCurrentProjectionPackage;
+ private LinearLayout mCurrentProjectionDetails;
+
+ private static final ImmutableMap<Integer, String> STATE_TO_STRING = ImmutableMap.of(
+ ProjectionStatus.PROJECTION_STATE_INACTIVE, "Inactive",
+ ProjectionStatus.PROJECTION_STATE_READY_TO_PROJECT, "Ready to project",
+ ProjectionStatus.PROJECTION_STATE_ACTIVE_FOREGROUND, "Foreground",
+ ProjectionStatus.PROJECTION_STATE_ACTIVE_BACKGROUND, "Background");
+
+ private static final ImmutableMap<Integer, String> TRANSPORT_TO_STRING = ImmutableMap.of(
+ ProjectionStatus.PROJECTION_TRANSPORT_NONE, "None",
+ ProjectionStatus.PROJECTION_TRANSPORT_USB, "USB",
+ ProjectionStatus.PROJECTION_TRANSPORT_WIFI, "WiFi");
+
+ private class KitchenSinkProjectionStatusListener implements ProjectionStatusListener {
+ @Override
+ public void onProjectionStatusChanged(
+ int state,
+ String packageName,
+ List<ProjectionStatus> details) {
+ mCurrentProjectionStatus.setText(STATE_TO_STRING.get(state));
+ mCurrentProjectionPackage.setText(packageName);
+ mCurrentProjectionDetails.removeAllViews();
+ for (ProjectionStatus detail : details) {
+ LinearLayout detailLayout =
+ (LinearLayout)
+ getLayoutInflater()
+ .inflate(R.layout.projection_status_details, null);
+
+ TextView detailPackage = detailLayout.findViewById(R.id.projection_detail_package);
+ detailPackage.setText(detail.getPackageName());
+
+ TextView detailState = detailLayout.findViewById(R.id.projection_detail_state);
+ detailState.setText(STATE_TO_STRING.get(detail.getState()));
+
+ TextView detailTransport =
+ detailLayout.findViewById(R.id.projection_detail_transport);
+ detailTransport.setText(TRANSPORT_TO_STRING.get(detail.getTransport()));
+
+ for (ProjectionStatus.MobileDevice device : detail.getConnectedMobileDevices()) {
+ LinearLayout deviceLayout =
+ (LinearLayout)
+ getLayoutInflater()
+ .inflate(R.layout.projection_status_device, null);
+
+ TextView deviceId = deviceLayout.findViewById(R.id.projection_device_id);
+ deviceId.setText(String.valueOf(device.getId()));
+
+ TextView deviceName = deviceLayout.findViewById(R.id.projection_device_name);
+ deviceName.setText(device.getName());
+
+ LinearLayout deviceTransports =
+ deviceLayout.findViewById(R.id.projection_device_transports);
+ for (Integer transport : device.getAvailableTransports()) {
+ TextView transportView = new TextView(mActivity);
+ transportView.setText(TRANSPORT_TO_STRING.get(transport));
+
+ deviceTransports.addView(transportView);
+ }
+
+ TextView deviceProjecting =
+ deviceLayout.findViewById(R.id.projection_device_projecting);
+ deviceProjecting.setText(String.valueOf(device.isProjecting()));
+
+ detailLayout.addView(deviceLayout);
+ }
+ mCurrentProjectionDetails.addView(detailLayout);
+ }
+ }
+ }
+
+ private final KitchenSinkProjectionStatusListener mProjectionListener =
+ new KitchenSinkProjectionStatusListener();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ mActivity = (KitchenSinkActivity) getActivity();
+ mCarProjectionManager = mActivity.getProjectionManager();
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater,
+ ViewGroup container,
+ Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.projection_status, container, false);
+
+ mCurrentProjectionStatus = (TextView) layout.findViewById(R.id.current_projection_status);
+ mCurrentProjectionPackage = (TextView) layout.findViewById(R.id.current_projection_package);
+ mCurrentProjectionDetails =
+ (LinearLayout) layout.findViewById(R.id.current_projection_details);
+
+ return layout;
+ }
+
+ @Override
+ public void onStart() {
+ mCarProjectionManager.registerProjectionStatusListener(mProjectionListener);
+ super.onStart();
+ }
+
+ @Override
+ public void onStop() {
+ mCarProjectionManager.unregisterProjectionStatusListener(mProjectionListener);
+ super.onStop();
+ }
+}
diff --git a/tests/InstrumentClusterRendererSample/Android.mk b/tests/InstrumentClusterRendererSample/Android.mk
deleted file mode 100644
index fc00dfa..0000000
--- a/tests/InstrumentClusterRendererSample/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := InstrumentClusterRendererSampleImpl
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# Each update should be signed by OEMs
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_JAVA_LIBRARIES += android.car
-
-LOCAL_USE_AAPT2 := true
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_STATIC_ANDROID_LIBRARIES += androidx.legacy_legacy-support-v4
-
-include $(BUILD_PACKAGE)
diff --git a/tests/InstrumentClusterRendererSample/AndroidManifest.xml b/tests/InstrumentClusterRendererSample/AndroidManifest.xml
deleted file mode 100644
index 6231220..0000000
--- a/tests/InstrumentClusterRendererSample/AndroidManifest.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.car.cluster.sample"
- android:sharedUserId="android.uid.system">
-
- <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="23"/>
-
- <!-- We set TYPE_SYSTEM_ALERT window flag to presentation in order
- to show it outside of activity context -->
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
-
- <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
-
- <application android:label="@string/app_name"
- android:icon="@drawable/ic_launcher"
- android:process="android.car.service"
- android:directBootAware="true">
- <service android:name="com.android.car.cluster.sample.ClusterInCallService"
- android:permission="android.permission.BIND_INCALL_SERVICE"
- android:exported="false">
- <meta-data android:name="android.telecom.METADATA_IN_CALL_UI"
- android:value="false" />
- <intent-filter>
- <action android:name="android.telecom.InCallService"/>
- </intent-filter>
- </service>
-
- <service android:name="com.android.car.cluster.sample.StatusBarNotificationListener"
- android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
- android:exported="false">
- <intent-filter>
- <action android:name="android.service.notification.NotificationListenerService" />
- </intent-filter>
- </service>
-
- <service android:name="com.android.car.cluster.sample.InstrumentClusterRenderingServiceImpl"
- android:exported="false"
- android:permission="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"
- />
- </application>
-</manifest>
diff --git a/tests/InstrumentClusterRendererSample/res/anim/icon_switcher_in.xml b/tests/InstrumentClusterRendererSample/res/anim/icon_switcher_in.xml
deleted file mode 100644
index 1c27b63..0000000
--- a/tests/InstrumentClusterRendererSample/res/anim/icon_switcher_in.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
--->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/linear"
- android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_longAnimTime" />
diff --git a/tests/InstrumentClusterRendererSample/res/anim/icon_switcher_out.xml b/tests/InstrumentClusterRendererSample/res/anim/icon_switcher_out.xml
deleted file mode 100644
index 6039c48..0000000
--- a/tests/InstrumentClusterRendererSample/res/anim/icon_switcher_out.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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.
--->
-
-<set>
- <!-- We hide this image only when a new one if fully visible, otherwise we may
- be in the state when we have 2 images semi-transparent, and even combined together they
- will look like semi-transparent it looks ugly when we have something underneath, e.g.
- when phone is answered.
- -->
- <alpha xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/linear"
- android:fromAlpha="1.0"
- android:toAlpha="0"
- android:startOffset="@android:integer/config_longAnimTime"
- android:duration="@android:integer/config_longAnimTime"/>
-</set>
diff --git a/tests/InstrumentClusterRendererSample/res/anim/slide_in_bottom.xml b/tests/InstrumentClusterRendererSample/res/anim/slide_in_bottom.xml
deleted file mode 100644
index 5739277..0000000
--- a/tests/InstrumentClusterRendererSample/res/anim/slide_in_bottom.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="50%p" android:toYDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime" />
-</set>
diff --git a/tests/InstrumentClusterRendererSample/res/anim/slide_out_top.xml b/tests/InstrumentClusterRendererSample/res/anim/slide_out_top.xml
deleted file mode 100644
index 2a92e26..0000000
--- a/tests/InstrumentClusterRendererSample/res/anim/slide_out_top.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="0" android:toYDelta="-50%p"
- android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:duration="@android:integer/config_mediumAnimTime" />
-</set>
diff --git a/tests/InstrumentClusterRendererSample/res/drawable-ldpi/ic_launcher.png b/tests/InstrumentClusterRendererSample/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 9923872..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable-ldpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/cloud_154_shadow.png b/tests/InstrumentClusterRendererSample/res/drawable/cloud_154_shadow.png
deleted file mode 100644
index 7275874..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/cloud_154_shadow.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/cloud_192.png b/tests/InstrumentClusterRendererSample/res/drawable/cloud_192.png
deleted file mode 100644
index 4fb90d3..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/cloud_192.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/cloud_384.png b/tests/InstrumentClusterRendererSample/res/drawable/cloud_384.png
deleted file mode 100644
index e74a3c6..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/cloud_384.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/cloud_96_shadow.png b/tests/InstrumentClusterRendererSample/res/drawable/cloud_96_shadow.png
deleted file mode 100644
index e73899c..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/cloud_96_shadow.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/gas_station_36.png b/tests/InstrumentClusterRendererSample/res/drawable/gas_station_36.png
deleted file mode 100644
index a766a2b..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/gas_station_36.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/hangouts_icon.png b/tests/InstrumentClusterRendererSample/res/drawable/hangouts_icon.png
deleted file mode 100644
index f7683f5..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/hangouts_icon.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/line_empty_divider.xml b/tests/InstrumentClusterRendererSample/res/drawable/line_empty_divider.xml
deleted file mode 100644
index cbaf65d..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/line_empty_divider.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <size android:height="5px" android:width="0dp"/>
-</shape>
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/phone.png b/tests/InstrumentClusterRendererSample/res/drawable/phone.png
deleted file mode 100644
index d4fb6fc..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/phone.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/phone_active.png b/tests/InstrumentClusterRendererSample/res/drawable/phone_active.png
deleted file mode 100644
index 8c941bb..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/phone_active.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/sun_154.png b/tests/InstrumentClusterRendererSample/res/drawable/sun_154.png
deleted file mode 100644
index 0103438..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/sun_154.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/drawable/unknown_contact_480.png b/tests/InstrumentClusterRendererSample/res/drawable/unknown_contact_480.png
deleted file mode 100644
index 9f864ca..0000000
--- a/tests/InstrumentClusterRendererSample/res/drawable/unknown_contact_480.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/layout/call_card.xml b/tests/InstrumentClusterRendererSample/res/layout/call_card.xml
deleted file mode 100644
index 8c024f3..0000000
--- a/tests/InstrumentClusterRendererSample/res/layout/call_card.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?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.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <LinearLayout android:id="@+id/phone_text_panel"
- android:layout_width="@dimen/card_message_panel_width"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_centerVertical="true">
- <TextView android:id="@+id/call_status"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/incoming_call"
- android:textColor="@color/cluster_font_secondary"
- android:fontFamily="@string/font_family_secondary"
- android:textSize="@dimen/font_size_large"/>
- <TextView android:id="@+id/contact_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@color/cluster_font_primary"
- android:textSize="@dimen/font_size_large"
- android:fontFamily="@string/font_family_primary"/>
- <LinearLayout android:id="@+id/call_duration_panel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Chronometer android:id="@+id/call_duration"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/cluster_font_secondary"
- android:fontFamily="@string/font_family_secondary"
- android:textSize="@dimen/font_size_large"/>
- <TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/dummy_call_type"
- android:textColor="@color/cluster_font_secondary"
- android:fontFamily="@string/font_family_secondary"
- android:textSize="@dimen/font_size_large"
- android:layout_marginLeft="@dimen/word_spacing"/>
- </LinearLayout>
- </LinearLayout>
-</merge>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/layout/card_view.xml b/tests/InstrumentClusterRendererSample/res/layout/card_view.xml
deleted file mode 100644
index 14fbd9d..0000000
--- a/tests/InstrumentClusterRendererSample/res/layout/card_view.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
--->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/card_width"
- android:layout_height="@dimen/card_height">
-
- <ImageView android:id="@+id/image_background"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:scaleType="centerCrop"
- android:visibility="gone"/>
-
- <include layout="@layout/icon_switcher" android:id="@+id/left_icon_switcher"/>
- <include layout="@layout/icon_switcher" android:id="@+id/right_icon_switcher"/>
-</RelativeLayout>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/layout/cluster_view.xml b/tests/InstrumentClusterRendererSample/res/layout/cluster_view.xml
deleted file mode 100644
index b6d192c..0000000
--- a/tests/InstrumentClusterRendererSample/res/layout/cluster_view.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
--->
-
-<LinearLayout android:id="@+id/root"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:keepScreenOn="true"
- android:orientation="horizontal"
- android:background="@color/cluster_background"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <View android:layout_width="0dp" android:layout_height="0dp" android:layout_weight="1"/>
- <com.android.car.cluster.sample.CardPanel
- android:id="@+id/card_panel"
- android:layout_width="@dimen/card_width"
- android:layout_height="@dimen/card_height">
-
- </com.android.car.cluster.sample.CardPanel>
-</LinearLayout>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/layout/hangout_layout.xml b/tests/InstrumentClusterRendererSample/res/layout/hangout_layout.xml
deleted file mode 100644
index fbd4f0d..0000000
--- a/tests/InstrumentClusterRendererSample/res/layout/hangout_layout.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?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.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <LinearLayout android:id="@+id/msg_text_panel"
- android:layout_width="@dimen/card_message_panel_width"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_centerVertical="true"
- android:showDividers="middle"
- android:divider="@drawable/line_empty_divider">
- <TextView android:id="@+id/msg_card_status"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/incoming_message"
- android:fontFamily="@string/font_family_secondary"
- android:textColor="@color/cluster_font_secondary"
- android:textSize="@dimen/font_size_large"/>
- <TextView android:id="@+id/msg_card_contact_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@color/cluster_font_primary"
- android:fontFamily="@string/font_family_primary"
- android:text="@string/unknown"
- android:textSize="@dimen/font_size_large"/>
- </LinearLayout>
-</merge>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/layout/icon_switcher.xml b/tests/InstrumentClusterRendererSample/res/layout/icon_switcher.xml
deleted file mode 100644
index 9bc4c5d..0000000
--- a/tests/InstrumentClusterRendererSample/res/layout/icon_switcher.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?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.
--->
-
-<ViewSwitcher xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/left_icon_switcher"
- android:layout_width="@dimen/card_icon_size"
- android:layout_height="@dimen/card_icon_size"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:inAnimation="@anim/icon_switcher_in"
- android:outAnimation="@anim/icon_switcher_out">
- <ImageView android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/transparent"
- android:scaleType="centerCrop"/>
- <ImageView android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/transparent"
- android:scaleType="centerCrop"/>
-</ViewSwitcher>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/layout/media_card.xml b/tests/InstrumentClusterRendererSample/res/layout/media_card.xml
deleted file mode 100644
index 62a574c..0000000
--- a/tests/InstrumentClusterRendererSample/res/layout/media_card.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?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.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Panel will be shown for media -->
- <LinearLayout android:id="@+id/message_panel"
- android:layout_width="@dimen/card_message_panel_width"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_centerVertical="true"
- android:showDividers="middle"
- android:divider="@drawable/line_empty_divider">
- <TextView android:id="@+id/media_title"
- android:layout_width="@dimen/card_message_panel_width"
- android:layout_height="wrap_content"
- android:textColor="@color/cluster_font_primary"
- android:textSize="@dimen/font_size_medium"
- android:fontFamily="sans-serif-medium"
- android:singleLine="false"/>
- <TextView android:id="@+id/media_subtitle"
- android:layout_width="@dimen/card_message_panel_width"
- android:layout_height="wrap_content"
- android:textColor="@color/cluster_font_secondary"
- android:textSize="@dimen/font_size_small"
- android:fontFamily="sans-serif-regular"
- android:singleLine="false"/>
- <ProgressBar
- android:id="@+id/progress_bar"
- android:progress="80"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="@dimen/media_card_progress_width"
- android:layout_height="@dimen/media_card_progress_height"
- android:layout_marginTop="@dimen/media_card_progress_margin_top"
- android:background="#3cf5f5f5"
- android:max="100"/>
- </LinearLayout>
-</merge>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/layout/nav_card.xml b/tests/InstrumentClusterRendererSample/res/layout/nav_card.xml
deleted file mode 100644
index adee49c..0000000
--- a/tests/InstrumentClusterRendererSample/res/layout/nav_card.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <ViewSwitcher android:id="@+id/nav_directions_switcher"
- android:layout_width="@dimen/card_message_panel_width"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:inAnimation="@anim/slide_in_bottom"
- android:outAnimation="@anim/slide_out_top">
- </ViewSwitcher>
-</merge>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/layout/nav_card_maneuver_description.xml b/tests/InstrumentClusterRendererSample/res/layout/nav_card_maneuver_description.xml
deleted file mode 100644
index ca5ec3e..0000000
--- a/tests/InstrumentClusterRendererSample/res/layout/nav_card_maneuver_description.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?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.
--->
-
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/nav_directions"
- android:layout_width="@dimen/card_message_panel_width"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:orientation="vertical">
- <!-- First line contains distance and units, e.g. 200 ft -->
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <TextView android:id="@+id/nav_distance"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/font_size_nav_distance"
- android:textColor="@color/cluster_font_primary"
- android:fontFamily="@string/font_family_primary"/>
- <TextView android:id="@+id/nav_distance_units"
- android:layout_marginLeft="@dimen/word_spacing"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/font_size_medium"
- android:textColor="@color/cluster_font_dark_gray"
- android:fontFamily="@string/font_family_secondary"
- android:text="@string/nav_distance_units_ft"/>
- </LinearLayout>
-
- <!-- Second line for street name -->
- <TextView android:id="@+id/nav_street"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/font_size_medium"
- android:textColor="@color/cluster_font_secondary"
- android:fontFamily="@string/font_family_secondary"/>
-</LinearLayout>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/layout/weather_card.xml b/tests/InstrumentClusterRendererSample/res/layout/weather_card.xml
deleted file mode 100644
index da01ffc..0000000
--- a/tests/InstrumentClusterRendererSample/res/layout/weather_card.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?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.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-
- <ImageView android:id="@+id/weather_near_cloud"
- android:layout_width="@dimen/weather_card_near_cloud"
- android:layout_height="@dimen/weather_card_near_cloud"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:src="@drawable/cloud_384"
- android:scaleType="fitXY"
- android:translationY="@dimen/weather_card_cloud_vertical_margin"
- android:layout_marginRight="@dimen/weather_card_near_margin_right"/>
- <ImageView android:id="@+id/weather_far_cloud"
- android:layout_width="@dimen/weather_card_far_cloud"
- android:layout_height="@dimen/weather_card_far_cloud"
- android:layout_centerHorizontal="true"
- android:layout_alignParentTop="true"
- android:src="@drawable/cloud_192"
- android:scaleType="fitXY"
- android:translationY="@dimen/weather_card_cloud_vertical_margin"/>
-
- <!-- Panel shown for the weather -->
- <LinearLayout android:id="@+id/weather_panel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:orientation="horizontal">
- <TextView android:id="@+id/weather_temperature"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:fontFamily="sans-serif-light"
- android:textColor="@color/cluster_font_primary"
- android:text="@string/dummy_weather_temperature"
- android:textSize="@dimen/speedo_speed_min_font_size"/>
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="center"
- android:paddingLeft="@dimen/weather_card_text_left_padding">
- <TextView android:id="@+id/weather_forecast"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/font_size_large"
- android:textColor="@color/cluster_font_primary"
- android:text="@string/dummy_weather_forecast"
- android:translationY="6px"/>
- <TextView android:id="@+id/weather_location"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/font_size_large"
- android:textColor="@color/cluster_font_secondary"
- android:fontFamily="@string/font_family_secondary"
- android:text="@string/dummy_weather_location"/>
- </LinearLayout>
- </LinearLayout>
-</merge>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/mipmap-hdpi/ic_launcher.png b/tests/InstrumentClusterRendererSample/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bc..0000000
--- a/tests/InstrumentClusterRendererSample/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/mipmap-mdpi/ic_launcher.png b/tests/InstrumentClusterRendererSample/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0c..0000000
--- a/tests/InstrumentClusterRendererSample/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/mipmap-xhdpi/ic_launcher.png b/tests/InstrumentClusterRendererSample/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0..0000000
--- a/tests/InstrumentClusterRendererSample/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/mipmap-xxhdpi/ic_launcher.png b/tests/InstrumentClusterRendererSample/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72c..0000000
--- a/tests/InstrumentClusterRendererSample/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/mipmap-xxxhdpi/ic_launcher.png b/tests/InstrumentClusterRendererSample/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e1..0000000
--- a/tests/InstrumentClusterRendererSample/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/InstrumentClusterRendererSample/res/values/attrs.xml b/tests/InstrumentClusterRendererSample/res/values/attrs.xml
deleted file mode 100644
index 9386437..0000000
--- a/tests/InstrumentClusterRendererSample/res/values/attrs.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?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>
-</resources>
diff --git a/tests/InstrumentClusterRendererSample/res/values/colors.xml b/tests/InstrumentClusterRendererSample/res/values/colors.xml
deleted file mode 100644
index 2b7698b..0000000
--- a/tests/InstrumentClusterRendererSample/res/values/colors.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?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>
- <color name="colorPrimary">#3F51B5</color>
- <color name="colorPrimaryDark">#303F9F</color>
- <color name="colorAccent">#FF4081</color>
-
- <color name="black_overlay">#66000000</color>
-
- <color name="cluster_background">#172026</color>
- <color name="speedo_inner_circle_shade">#770c1013</color>
- <color name="cluster_active_area_background">#ff141c21</color>
- <color name="cluster_black">#ff0c1013</color>
- <color name="cluster_font_primary">#fff5f5f5</color>
- <color name="cluster_font_secondary">#8af5f5f5</color>
- <!-- Speed unit -->
- <color name="cluster_font_light_gray">#ffd8d9da</color>
- <!-- Phone call duration / album -->
- <color name="cluster_font_dark_gray">#ffa6a9ab</color>
-
- <color name="media_icon_foreground">#ff202020</color>
-
- <color name="media_background">#ff444444</color>
- <color name="media_background_dark">#ff303030</color>
-
- <color name="phone_background">#ff01579b</color>
- <color name="phone_background_dark">#ff014174</color>
- <color name="phone_icon_background">#ff0277bd</color>
- <color name="phone_font_incoming_call">#ffa3c1d9</color>
-
- <color name="maps_background">#ff0d904f</color>
-
- <color name="speedo_minute_arm_color_begin">#ffffcbbb</color>
- <color name="speedo_minute_arm_color_mid">#ffffcbbb</color>
- <color name="speedo_minute_arm_color_end">#ffffcbbb</color>
- <color name="speedo_minute_arm_color_border">#77ffcbbb</color>
- <color name="speedo_clock_nail">#ffffcbbb</color>
-
- <color name="speedo_clock_nail_shadow_start">#33000000</color>
- <color name="speedo_clock_nail_shadow_mid">#22000000</color>
- <color name="speedo_clock_nail_shadow_end">#00000000</color>
- <color name="speedo_clock_nail_shadow">#33000000</color>
-
- <color name="speedo_hour_arm_color_mid">@color/cluster_font_primary</color>
- <color name="speedo_hour_arm_color_start">@color/cluster_font_primary</color>
- <color name="speedo_hour_arm_color_end">@color/cluster_font_primary</color>
- <color name="speedo_hour_arm_color_border">#77f5f5f5</color>
-
- <color name="weather_blue_sky">#ff4385f4</color>
- <color name="weather_sun">#fffdbf2d</color>
- <color name="weather_cloud">#fffffeff</color>
- <color name="weather_location_text">#ffb2d1ff</color>
-
- <color name="hangout_background">#ff086934</color>
- <color name="hangout_icon_background">#ff086934</color>
- <color name="hangout_incoming_message_font_color">#ffa5c7b5</color>
- <color name="hangout_background_dark">#ff054422</color>
-
-</resources>
diff --git a/tests/InstrumentClusterRendererSample/res/values/dimens.xml b/tests/InstrumentClusterRendererSample/res/values/dimens.xml
deleted file mode 100644
index 66d54de..0000000
--- a/tests/InstrumentClusterRendererSample/res/values/dimens.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?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>
- <dimen name="cluster_width">1920px</dimen>
- <dimen name="cluster_height">720px</dimen>
-
- <dimen name="fuel_panel_width">360px</dimen>
-
- <dimen name="speedo_margin_top">43px</dimen>
- <dimen name="speed_units_margin_from_center">165px</dimen>
- <dimen name="speedo_outer_circle_diameter">651px</dimen>
- <dimen name="speedo_inner_circle_min_diameter">232px</dimen>
- <dimen name="speedo_speed_min_font_size">@dimen/font_size_xlarge</dimen>
- <dimen name="speedo_speed_max_font_size">@dimen/font_size_xxlarge</dimen>
-
- <dimen name="speedo_inner_circle_max_diameter">540px</dimen>
- <dimen name="speedo_minute_arm_width">232px</dimen>
- <dimen name="speedo_minute_arm_width_half">116px</dimen>
- <dimen name="speedo_hour_arm_width">160px</dimen>
- <dimen name="speedo_hour_arm_width_half">80px</dimen>
- <dimen name="speedo_clock_nail">52px</dimen>
- <dimen name="speedo_border_width">1px</dimen>
-
- <dimen name="speedo_arm_height">8px</dimen>
- <dimen name="speedo_arm_center">4px</dimen>
-
-
- <dimen name="card_width">909px</dimen>
- <dimen name="card_height">@dimen/cluster_height</dimen>
- <dimen name="card_icon_size">154px</dimen>
- <dimen name="card_background_image_width">780px</dimen>
- <dimen name="card_message_panel_width">500px</dimen>
- <dimen name="card_content_left_padding">40px</dimen>
-
- <dimen name="word_spacing">10px</dimen>
-
- <dimen name="font_size_nav_distance">56px</dimen>
-
- <dimen name="font_size_xxlarge">152px</dimen>
- <dimen name="font_size_xlarge">120px</dimen>
- <dimen name="font_size_large">45px</dimen>
- <dimen name="font_size_medium">36px</dimen>
- <dimen name="font_size_small">26px</dimen>
- <dimen name="font_size_xsmall">22px</dimen>
-
- <dimen name="font_size_drive_state">@dimen/font_size_large</dimen>
-
- <dimen name="weather_card_near_cloud">384px</dimen>
- <dimen name="weather_card_near_margin_right">60px</dimen>
- <dimen name="weather_card_far_cloud">192px</dimen>
- <dimen name="weather_card_cloud_vertical_margin">40px</dimen>
- <dimen name="weather_card_text_left_padding">20px</dimen>
-
- <dimen name="media_card_progress_width">210px</dimen>
- <dimen name="media_card_progress_height">2px</dimen>
- <dimen name="media_card_progress_margin_top">12px</dimen>
-
- <dimen name="drive_state_size">144px</dimen>
- <dimen name="drive_state_inner_diameter">84px</dimen>
-
- <dimen name="fuel_indicator_width">@dimen/drive_state_size</dimen>
- <dimen name="fuel_indicator_radius">72px</dimen> <!-- fuel_indicator_width / 2 -->
- <dimen name="fuel_indicator_height">224px</dimen>
- <dimen name="fuel_indicator_inner_padding">30px</dimen> <!-- (width - inner_diameter) / 2 -->
- <dimen name="fuel_indicator_inner_padding_half">15px</dimen> <!-- padding / 2 -->
- <dimen name="fuel_indicator_inner_height">168px</dimen> <!-- height - padding * 2 -->
- <dimen name="fuel_indicator_inner_width">@dimen/drive_state_inner_diameter</dimen>
- <dimen name="fuel_indicator_inner_radius">42px</dimen> <!-- fuel_indicator_inner_diameter / 2 -->
- <dimen name="fuel_indicator_border_width">1px</dimen>
- <dimen name="fuel_panel_margin_right">40px</dimen>
-</resources>
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/res/values/strings.xml b/tests/InstrumentClusterRendererSample/res/values/strings.xml
deleted file mode 100644
index 2666619..0000000
--- a/tests/InstrumentClusterRendererSample/res/values/strings.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?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:xliff="http://schemas.android.com/tools">
- <string name="app_name" translatable="false">InstrumentClusterRendererImpl</string>
-
- <string name="incoming_call" translatable="false">Incoming call</string>
- <string name="dialing" translatable="false">Dialing</string>
- <string name="dummy_call_type" translatable="false">• Mobile</string>
-
- <string name="font_family_primary" translatable="false">sans-serif-medium</string>
- <string name="font_family_secondary" translatable="false">sans-serif-regular</string>
-
- <string name="dummy_weather_forecast" translatable="false">Partly cloudy</string>
- <string name="dummy_weather_location" translatable="false">Mountain View, CA</string>
- <string name="dummy_weather_temperature" translatable="false">82°</string>
-
- <string name="nav_distance_units_ft" translatable="false">ft</string>
- <string name="nav_distance_units_meters" translatable="false">m</string>
- <string name="nav_distance_units_kilometers" translatable="false">km</string>
- <string name="nav_distance_units_miles" translatable="false">mi</string>
- <string name="nav_distance_units_yards" translatable="false">yd</string>
-
- <string name="incoming_message" translatable="false">Incoming message</string>
-
- <string name="unknown" translatable="false">Unknown</string>
- <string name="voicemail" translatable="false">Voicemail</string>
- <string name="phone_label_with_info" translatable="false">
- <xliff:g id="label" example="Mobile">%1$s</xliff:g>
- " \u00B7 "
- <xliff:g id="duration" example="1:20">%2$s</xliff:g>
- </string>
- <!-- Status label for phone state [CHAR LIMIT=20] -->
- <string name="call_state_connecting" translatable="false">Connecting</string>
- <!-- Status label for phone state [CHAR LIMIT=20] -->
- <string name="call_state_dialing" translatable="false">Dialing</string>
- <!-- Status label for phone state [CHAR LIMIT=20] -->
- <string name="call_state_hold" translatable="false">On Hold</string>
- <!-- Status label for phone state [CHAR LIMIT=20] -->
- <string name="call_state_call_ended" translatable="false">Call Ended</string>
- <!-- Status label for phone state [CHAR LIMIT=20] -->
- <string name="call_state_call_active" translatable="false">Connected</string>
- <!-- Status label for phone state [CHAR LIMIT=20] -->
- <string name="call_state_call_ringing" translatable="false">Ringing</string>
- <!-- Status label for phone state [CHAR LIMIT=20] -->
- <string name="call_state_call_ending" translatable="false">Disconnecting</string>
-
-</resources>
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/BitmapUtils.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/BitmapUtils.java
deleted file mode 100644
index 430bf35..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/BitmapUtils.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-import static android.graphics.Color.blue;
-import static android.graphics.Color.green;
-import static android.graphics.Color.red;
-
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-
-/**
- * Utility functions to work with bitmaps.
- */
-public class BitmapUtils {
-
- // Non-transparent color to crop images using Xfermode.
- private static final int OPAQUE_COLOR = 0xff424242;
-
- /**
- * Scales a bitmap while preserving the proportions such that both dimensions are the smallest
- * values possible that are equal to or larger than the given dimensions.
- *
- * This function can be a few times as expensive as Bitmap.createScaledBitmap with
- * filtering when downscaling, but it produces much nicer results.
- *
- * @param bm The bitmap to scale.
- * @param width The desired width.
- * @param height The desired height.
- * @return The scaled bitmap, or the original bitmap if scaling was not necessary.
- */
- public static Bitmap scaleBitmap(Bitmap bm, int width, int height) {
- if (bm == null || (bm.getHeight() == height && bm.getWidth() == width)) {
- return bm;
- }
-
- float heightScale = (float) height / bm.getHeight();
- float widthScale = (float) width / bm.getWidth();
-
- float scale = heightScale > widthScale ? heightScale : widthScale;
- int scaleWidth = (int) Math.ceil(bm.getWidth() * scale);
- int scaleHeight = (int) Math.ceil(bm.getHeight() * scale);
-
- Bitmap scaledBm = bm;
- // If you try to scale an image down too much in one go, you can end up with discontinuous
- // interpolation. Therefore, if necessary, we scale the image to twice the desired size
- // and do a second scaling to the desired size, which smooths jaggedness from the first go.
- if (scale < .5f) {
- scaledBm = Bitmap.createScaledBitmap(scaledBm, scaleWidth * 2, scaleHeight * 2, true);
- }
-
- if (scale != 1f) {
- Bitmap newScaledBitmap = Bitmap
- .createScaledBitmap(scaledBm, scaleWidth, scaleHeight, true);
- if (scaledBm != bm) {
- scaledBm.recycle();
- }
- scaledBm = newScaledBitmap;
- }
- return scaledBm;
- }
-
- public static Bitmap squareCropBitmap(Bitmap bitmap) {
- if (bitmap.getWidth() == bitmap.getHeight()) {
- return bitmap;
- }
-
- int size = Math.min(bitmap.getWidth(), bitmap.getHeight());
-
- Bitmap output = Bitmap.createBitmap(size,
- size, Config.ARGB_8888);
- Canvas canvas = new Canvas(output);
-
- int x = size < bitmap.getWidth() ? (bitmap.getWidth() - size ) / 2 : 0;
- int y = size < bitmap.getHeight() ? (bitmap.getHeight() - size ) / 2 : 0;
- Rect srcRect = new Rect(x, y, x + size, y + size);
- Rect dstRect = new Rect(0, 0, output.getWidth(), output.getHeight());
-
- canvas.drawBitmap(bitmap, srcRect, dstRect, null);
- return output;
- }
-
- public static Bitmap circleCropBitmap(Bitmap bitmap) {
- bitmap = squareCropBitmap(bitmap);
- Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
- bitmap.getHeight(), Config.ARGB_8888);
- Canvas canvas = new Canvas(output);
-
- Paint paint = new Paint();
- Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
-
- paint.setAntiAlias(true);
- canvas.drawARGB(0, 0, 0, 0);
- paint.setColor(OPAQUE_COLOR);
- canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
- bitmap.getWidth() / 2, paint);
- paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
- canvas.drawBitmap(bitmap, rect, rect, paint);
- return output;
- }
-
- public static Bitmap generateNavManeuverIcon(int size, int bgColor, Bitmap maneuver) {
- Bitmap bm = Bitmap.createBitmap(size, size, Config.ARGB_8888);
- Canvas canvas = new Canvas(bm);
- drawCircle(canvas, bgColor);
-
- canvas.drawBitmap(maneuver,
- (bm.getWidth() - maneuver.getWidth()) / 2,
- (bm.getHeight() - maneuver.getHeight()) / 2,
- new Paint(Paint.ANTI_ALIAS_FLAG));
- return bm;
- }
-
- public static Bitmap generateMediaIcon(int size, int bgColor, int fgColor) {
- final float goldenRatio = 1.618f;
-
- Bitmap bm = Bitmap.createBitmap(size, size, Config.ARGB_8888);
- Canvas canvas = new Canvas(bm);
- drawCircle(canvas, bgColor);
-
- // Calculate column parameters relative to the size.
- int bottom = (int) (size / goldenRatio);
- int columnWidth = size / 17;
- int columnSpace = columnWidth / 2;
- int allColumnsWidth = columnWidth * 3 + columnSpace * 2;
- int left = size / 2 - (allColumnsWidth) / 2;
-
- Paint columnPaint = new Paint();
- columnPaint.setColor(fgColor);
- columnPaint.setAntiAlias(true);
- canvas.drawRect(new RectF(left, bottom - columnWidth * 2, left + columnWidth, bottom),
- columnPaint);
-
- left += columnWidth + columnSpace;
- canvas.drawRect(new RectF(left, bottom - columnWidth * 4, left + columnWidth, bottom),
- columnPaint);
-
- left += columnWidth + columnSpace;
- canvas.drawRect(new RectF(left, bottom - columnWidth * 3, left + columnWidth, bottom),
- columnPaint);
-
- return bm;
- }
-
- private static Canvas drawCircle(Canvas canvas, int bgColor) {
- int size = canvas.getWidth();
- Paint p = new Paint();
- p.setAntiAlias(true);
- p.setColor(bgColor);
- canvas.drawCircle(size / 2, size / 2, (size / 2) - 1, p);
- return canvas;
- }
-
- public static int[] getBaseColors(int color) {
- return new int[] {red(color), green(color), blue(color)};
- }
-
- /**
- * Scales colors for given bitmap. This could be used as color filter for example.
- */
- public static Bitmap scaleBitmapColors(Bitmap original, int minColor, int maxColor) {
- int[] pixels = new int[original.getWidth() * original.getHeight()];
- original.getPixels(pixels, 0, original.getWidth(), 0, 0,
- original.getWidth(), original.getHeight());
-
- int[] min = getBaseColors(minColor);
- int[] max = getBaseColors(maxColor);
-
- for (int i = 0; i < pixels.length; i++) {
- int pixel = pixels[i];
- int[] colors = new int[] {red(pixel), green(pixel), blue(pixel)};
-
- for (int j = 0; j < 3; j++) {
- colors[j] = (int)((colors[j] / 255.0) * (max[j] - min[j]) + min[j]);
- }
-
- pixels[i] = Color.rgb(colors[0], colors[1], colors[2]);
- }
-
- Bitmap bmp = Bitmap.createBitmap(original.getWidth(), original.getHeight(), Config.ARGB_8888);
- bmp.setPixels(pixels, 0, original.getWidth(), 0, 0, original.getWidth(),
- original.getHeight());
- return bmp;
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/CardPanel.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/CardPanel.java
deleted file mode 100644
index 88c2aba..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/CardPanel.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Panel that responsible of holding cards.
- */
-public class CardPanel extends FrameLayout {
- private final static String TAG = DebugUtil.getTag(CardPanel.class);
-
- private final List<View> mOrderedChildren = new ArrayList<>(10);
- private final Set<View> mViewsToBeRemoved = new HashSet<>();
-
- public CardPanel(Context context) {
- this(context, null);
- }
-
- public CardPanel(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public CardPanel(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- setChildrenDrawingOrderEnabled(true);
- }
-
- @Override
- public void addView(View child, int index) {
- super.addView(child, index);
- if (index < 0) {
- mOrderedChildren.add(child);
- } else {
- mOrderedChildren.add(index, child);
- }
- }
-
- @Override
- public void removeView(View view) {
- super.removeView(view);
-
- mOrderedChildren.remove(view);
- mViewsToBeRemoved.remove(view);
- }
-
- /**
- * If we are removing view with animation, we do not want to treat this view as visible.
- */
- public void markViewToBeRemoved(View view) {
- mViewsToBeRemoved.add(view);
- }
-
-
- public boolean childViewExists(View child) {
- return indexOfChild(child) >= 0 && !mViewsToBeRemoved.contains(child);
- }
-
- /** Moves given child behind the top card */
- public void moveChildBehindTheTop(View child) {
- if (mOrderedChildren.size() <= 1) {
- return;
- }
-
- int newIndex = mOrderedChildren.size() - 2;
- int oldIndex = mOrderedChildren.indexOf(child);
- if (oldIndex == -1) {
- Log.e(TAG, "Child: " + child + " not found in "
- + Arrays.toString(mOrderedChildren.toArray()));
- return;
- }
- if (newIndex == oldIndex) {
- return;
- }
-
- // Swap children.
- View tmpChild = mOrderedChildren.get(newIndex);
- mOrderedChildren.set(newIndex, child);
- mOrderedChildren.set(oldIndex, tmpChild);
- }
-
- public View getTopVisibleChild() {
- for (int i = mOrderedChildren.size() - 1; i >= 0; i--) {
- View child = mOrderedChildren.get(i);
- if (child.getVisibility() == VISIBLE && !mViewsToBeRemoved.contains(child)) {
- return child;
- }
- }
- return null;
- }
-
- @SuppressWarnings("unchecked")
- public <E> E getChildOrNull(Class<E> clazz) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (clazz.isInstance(child) && !mViewsToBeRemoved.contains(child)) {
- return (E) child;
- }
- }
- return null;
- }
-
- @SuppressWarnings("unchecked")
- public <E> E getVisibleChildOrNull(Class<E> clazz) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (clazz.isInstance(child) && !mViewsToBeRemoved.contains(child)
- && child.getVisibility() == VISIBLE) {
- return (E) child;
- }
- }
- return null;
- }
-
- @Override
- protected int getChildDrawingOrder(int childCount, int i) {
- return indexOfChild(mOrderedChildren.get(i));
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/ClusterInCallService.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/ClusterInCallService.java
deleted file mode 100644
index 8348a2b..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/ClusterInCallService.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-import static com.android.car.cluster.sample.DebugUtil.DEBUG;
-
-import android.content.Intent;
-import android.os.Binder;
-import android.os.IBinder;
-import android.telecom.Call;
-import android.telecom.Call.Callback;
-import android.telecom.InCallService;
-import android.util.Log;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Monitors call state and reports it to the listeners that was registered using
- * {@link #registerListener} method.
- */
-public class ClusterInCallService extends InCallService {
-
- private static final String TAG = DebugUtil.getTag(ClusterInCallService.class);
-
- static final String ACTION_LOCAL_BINDING = "local_binding";
-
- private final PhoneCallback mPhoneCallback = new PhoneCallback(this);
- private volatile Callback mListener;
-
- @Override
- public void onCallAdded(Call call) {
- if (DEBUG) {
- Log.d(TAG, "onCallAdded");
- }
- call.registerCallback(mPhoneCallback);
- mPhoneCallback.onStateChanged(call, call.getState());
- }
-
- @Override
- public void onCallRemoved(Call call) {
- if (DEBUG) {
- Log.d(TAG, "onCallRemoved");
- }
- call.unregisterCallback(mPhoneCallback);
- }
-
- private void doStateChanged(Call call, int state) {
- if (DEBUG) {
- Log.d(TAG, "doStateChanged, call: " + call + ", state: " + state);
- }
- if (mListener != null) {
- mListener.onStateChanged(call, state);
- }
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- Log.d(TAG, "onBind, intent:" + intent);
- return ACTION_LOCAL_BINDING.equals(intent.getAction())
- ? new LocalBinder() : super.onBind(intent);
- }
-
- public class LocalBinder extends Binder {
- ClusterInCallService getService() {
- return ClusterInCallService.this;
- }
- }
-
- public void registerListener(Callback listener) {
- Log.d(TAG, "registerListener, listener: " + listener);
- mListener = listener;
- }
-
- private static class PhoneCallback extends Callback {
- private final WeakReference<ClusterInCallService> mServiceRef;
-
- private PhoneCallback(ClusterInCallService service) {
- mServiceRef = new WeakReference<>(service);
- }
-
- @Override
- public void onStateChanged(Call call, int state) {
- Log.d(TAG, "PhoneCallback#onStateChanged, call: " + call + ", state: " + state);
- ClusterInCallService service = mServiceRef.get();
- if (service != null) {
- service.doStateChanged(call, state);
- }
- }
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/ClusterView.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/ClusterView.java
deleted file mode 100644
index 7b4255c..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/ClusterView.java
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-import static com.android.car.cluster.sample.BitmapUtils.generateMediaIcon;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewAnimationUtils;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.Animation.AnimationListener;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.Transformation;
-import android.view.animation.TranslateAnimation;
-import android.widget.FrameLayout;
-import android.widget.RelativeLayout;
-
-import com.android.car.cluster.sample.cards.CallCard;
-import com.android.car.cluster.sample.cards.CallCard.CallStatus;
-import com.android.car.cluster.sample.cards.CardView;
-import com.android.car.cluster.sample.cards.CardView.CardType;
-import com.android.car.cluster.sample.cards.MessageCard;
-import com.android.car.cluster.sample.cards.MediaCard;
-import com.android.car.cluster.sample.cards.NavCard;
-import com.android.car.cluster.sample.cards.WeatherCard;
-
-import java.util.PriorityQueue;
-
-/**
- * Class that represents cluster view. It is responsible of ranking cards and play animations
- * during card transitions.
- */
-public class ClusterView extends FrameLayout implements CardView.PriorityChangedListener{
- private static final String TAG = DebugUtil.getTag(ClusterView.class);
-
- private CardPanel mCardPanel;
-
- private final Handler mHandler = new Handler(Looper.getMainLooper());
- private final PriorityQueue<CardView> mQueue = new PriorityQueue<>(8);
-
- public ClusterView(Context context) {
- this(context, null);
- }
-
- public ClusterView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- inflate(getContext(), R.layout.cluster_view, this);
- mCardPanel = (CardPanel) findViewById(R.id.card_panel);
- }
-
- private <E extends CardView> E createCard(@CardType int cardType) {
- CardView card;
- switch (cardType)
- {
- case CardType.WEATHER:
- card = new WeatherCard(getContext(), this /* priority listener */);
- break;
- case CardType.MEDIA:
- card = new MediaCard(getContext(), this /* priority listener */);
- break;
- case CardType.PHONE_CALL:
- card = new CallCard(getContext(), this /* priority listener */);
- break;
- case CardType.NAV:
- card = new NavCard(getContext(), this /* priority listener */);
- break;
- case CardType.HANGOUT:
- card = new MessageCard(getContext(), this /* priority listener */);
- break;
- default:
- card = new CardView(getContext(), cardType, this /* priority listener */);
- }
- RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
- card.setLayoutParams(params);
- return (E) card;
- }
-
- public void handleIncomingCall(Bitmap contactImage, String contactName) {
- if (contactImage == null) {
- contactImage = BitmapFactory.decodeResource(getResources(),
- R.drawable.unknown_contact_480);
- }
- CardView card = createIncomingCallCard(contactImage, contactName);
- enqueueCard(card);
- }
-
- public void handleDialingCall(Bitmap contactImage, String contactName) {
- if (contactImage == null) {
- contactImage = BitmapFactory.decodeResource(getResources(),
- R.drawable.unknown_contact_480);
- }
- CardView card = createDialingCallCard(contactImage, contactName);
- enqueueCard(card);
- }
-
- public void handleUpdateContactName(String contactName) {
- CallCard card = getCallCard();
- if (card != null) {
- card.setContactName(contactName);
- }
- }
-
- public void handleUpdateContactImage(Bitmap image) {
- CallCard card = getCallCard();
- if (card != null) {
- updateContactImage(card, image);
- }
- }
-
- public void handleHangoutMessage(Bitmap contactImage, String contactName) {
- if (getCardOrNull(MessageCard.class) != null) {
- return; // Deduplicate.
- }
-
- if (contactImage == null) {
- contactImage = BitmapFactory.decodeResource(getResources(),
- R.drawable.unknown_contact_480);
- }
- MessageCard card = createCard(CardType.HANGOUT);
- card.setContactName(contactName);
-
- int c = getResources().getColor(R.color.hangout_background, null);
- card.setBackgroundColor(c);
- card.setLeftIcon(BitmapUtils.circleCropBitmap(contactImage));
-
- enqueueCard(card);
- }
-
- public void handleCallConnected(long connectedTimestamp) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "handleCallConnected, connectedTimestamp: " + connectedTimestamp);
- }
- CallCard card = getCallCard();
- if (card != null) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "handleCallConnected, call status: " + card.getCallStatus());
- }
-
- if (card.getCallStatus() == CallStatus.INCOMING_OR_DIALING) {
- card.animateCallConnected(connectedTimestamp);
- }
- }
- }
-
- public void handleCallDisconnected() {
- final CallCard callCard = getCallCard();
- if (callCard != null) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "handleCallDisconnected, callCard status: " + callCard.getCallStatus());
- }
-
- if (callCard == getCurrentCard()
- && callCard.getCallStatus() == CallStatus.ACTIVE) {
- callCard.animateCallDisconnected();
- } else {
- removeCard(callCard);
- }
- }
- }
-
- public void runDelayed(long delay, final Runnable task) {
- mHandler.postDelayed(task, delay);
- }
-
- public MediaCard createMediaCard(Bitmap albumCover, String title, String subtitle,
- int appColor) {
- MediaCard card = createCard(CardType.MEDIA);
- int iconSize = card.getIconSize();
-
- if (albumCover != null) {
- Bitmap albumIcon = BitmapUtils.scaleBitmap(albumCover, iconSize, iconSize);
- albumIcon = BitmapUtils.circleCropBitmap(albumIcon);
- card.setLeftIcon(albumIcon);
-
- Bitmap backgroundImage = BitmapUtils.scaleBitmapColors(albumCover,
- getResources().getColor(R.color.media_background_dark, null),
- getResources().getColor(R.color.media_background, null));
-
- backgroundImage = BitmapUtils.scaleBitmap(backgroundImage,
- (int) (getResources().getDimension(R.dimen.card_width)),
- (int) getResources().getDimension(R.dimen.card_height));
-
- int c = getResources().getColor(R.color.phone_background, null);
- card.setBackground(backgroundImage, c);
- }
-
- Bitmap mediaApp = generateMediaIcon(iconSize,
- appColor,
- getResources().getColor(R.color.media_icon_foreground, null));
- card.setRightIcon(mediaApp);
- card.setProgressColor(appColor);
- card.setTitle(title);
- card.setSubtitle(subtitle);
- return card;
- }
-
- public CardView getCurrentCard() {
- return (CardView) mCardPanel.getTopVisibleChild();
- }
-
- public CardView createWeatherCard() {
- CardView card;
- card = createCard(CardType.WEATHER);
- card.setBackgroundColor(getResources().getColor(R.color.weather_blue_sky, null));
- return card;
- }
-
- public CallCard createIncomingCallCard(Bitmap contactImage, String contactName) {
- CallCard card = createCard(CardType.PHONE_CALL);
- updateContactImage(card, contactImage);
- card.setContactName(contactName);
- card.setStatusLabel(getContext().getString(R.string.incoming_call));
- return card;
- }
-
- public CallCard createDialingCallCard(Bitmap contactImage, String contactName) {
- CallCard card = createCard(CardType.PHONE_CALL);
-
- updateContactImage(card, contactImage);
- card.setContactName(contactName);
- card.setStatusLabel(getContext().getString(R.string.dialing));
- return card;
- }
-
- public NavCard createNavCard() {
- return createCard(CardType.NAV);
- }
-
- private void updateContactImage(CardView card, Bitmap contactImage) {
- int iconSize = (int)getResources().getDimension(R.dimen.card_icon_size);
- Bitmap contactImageCircle = BitmapUtils.circleCropBitmap(
- BitmapUtils.scaleBitmap(contactImage, iconSize, iconSize));
- card.setLeftIcon(contactImageCircle);
-
- contactImage = BitmapUtils.scaleBitmapColors(contactImage,
- getResources().getColor(R.color.phone_background_dark, null),
- getResources().getColor(R.color.phone_background, null));
-
- contactImage = BitmapUtils.scaleBitmap(contactImage,
- (int) getResources().getDimension(R.dimen.card_width),
- (int) getResources().getDimension(R.dimen.card_height));
-
- int c = getResources().getColor(R.color.phone_background, null);
- card.setBackground(contactImage, c);
- }
-
- public boolean cardExists(CardView card) {
- return mCardPanel.childViewExists(card);
- }
-
- public void removeCard(final CardView card) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "removeCard, card: " + card);
- }
- final CardView currentlyShownCard = getCurrentCard();
- if (currentlyShownCard == card) {
- // Card is on the screen, play nice animation and then remove it.
- mQueue.remove(card);
- mCardPanel.markViewToBeRemoved(card);
- CardView cardToShow = mQueue.peek();
- if (cardToShow != null) {
- Animation animation = cardToShow.getAnimation();
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "card to show: " + cardToShow + ", animation: " + animation);
- }
- if (animation != null) {
- cardToShow.getAnimation().cancel();
- }
-
- cardToShow.setVisibility(VISIBLE);
- mCardPanel.moveChildBehindTheTop(cardToShow);
- }
- playUnrevealAnimation(card, new Runnable() {
- @Override
- public void run() {
- removeCardInternal(card);
- }
- });
- } else {
- // Card is not on the screen, just remove it.
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "removeCard, card is not on the screen, remove it immediately");
- removeCardInternal(card);
- }
- }
- }
-
- public void enqueueCard(final CardView card) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "enqueueCard, card: " + card);
- }
- final CardView currentCard = getCurrentCard();
- boolean cardIsOnTheScreen = card == currentCard;
-
- boolean cardExisted = mQueue.remove(card);
- mQueue.offer(card);
-
- CardView activeCard = mQueue.peek();
- boolean shouldDisplayCard = activeCard == card;
-
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "enqueueCard, card: " + card + ", onScreen: "
- + cardIsOnTheScreen + ", cardExisted: " + cardExisted + ", shouldDisplayCard: "
- + shouldDisplayCard + ", activeCard: " + activeCard
- + ", currentCard: " + currentCard);
- }
-
- if (cardIsOnTheScreen) {
- if (!shouldDisplayCard) {
- // Card priority was decreased, but it still active. Need to reverse reveal
- // animation and show underlying card.
- showCardWithFadeoutAnimation(activeCard);
- }
- } else {
- // Card is not on the screen right now.
- if (cardExisted) {
- if (shouldDisplayCard) {
- // Card was created in the past and is in the queue, need to show
- // this card using unreveal animation.
- showCardWithUnrevealAnimation(card);
- }
- } else {
- if (shouldDisplayCard) {
- // Card doesn't exist, but we want to show it.
- showCardWithRevealAnimation(card);
- } else {
- // We want to add the card to the panel, but do not want to show it.
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "Adding hidden card");
- }
- card.setVisibility(GONE);
- mCardPanel.addView(card, 0);
- }
- }
- }
-
- removeInvisibleDuplicatedCard(card); // Remove invisible cards with the same card type.
-
- dumpCardsToLog();
- }
-
- private void showCardWithRevealAnimation(final CardView cardToShow) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "showCardWithRevealAnimation, card: " + cardToShow);
- }
-
- removeInvisibleDuplicatedCard(cardToShow);
-
- CardView currentCard = getCurrentCard();
- mCardPanel.addView(cardToShow);
- playRevealAnimation(cardToShow, currentCard, new RemoveOrHideCard(this, currentCard));
- }
-
- private void removeInvisibleDuplicatedCard(CardView card) {
- Log.d(TAG, "removeInvisibleDuplicatedCard, card: " + card);
- // Remove cards that has the same card type and not visible on the screen.
- for (int i = mCardPanel.getChildCount() - 1; i >= 0; i--) {
- CardView child = (CardView) mCardPanel.getChildAt(i);
- if (child.getCardType() == card.getCardType()
- && child != card
- && child.getVisibility() != VISIBLE) {
- Log.d(TAG, "removeInvisibleDuplicatedCard, found dup: " + child);
- removeCardInternal(child);
- }
- }
- }
-
- private void showCardWithFadeoutAnimation(final CardView cardToShow) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "showCardWithFadeoutAnimation, card: " + cardToShow);
- }
- // Place card behind the top card, it will become visible once fade out animation for the
- // top card starts to play.
- mCardPanel.moveChildBehindTheTop(cardToShow);
- cardToShow.setVisibility(VISIBLE);
-
- // Hide top card with animation.
- playFadeOutAndSlideOutAnimation((CardView) mCardPanel.getTopVisibleChild());
- }
-
- private void showCardWithUnrevealAnimation(CardView cardToShow) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "showCardWithUnrevealAnimation, card: " + cardToShow);
- }
- final CardView currentCard = (CardView) mCardPanel.getTopVisibleChild();
- // Card was created in the past and is in the queue, need to show reverse reveal
- // animation to unreveal this card.
- mCardPanel.moveChildBehindTheTop(cardToShow);
- cardToShow.setVisibility(VISIBLE);
- playUnrevealAnimation(currentCard, new RemoveOrHideCard(this, currentCard));
- }
-
- private static class RemoveOrHideCard implements Runnable {
- private final CardView mCard;
-
- private final ClusterView mClusterView;
-
- RemoveOrHideCard(ClusterView clusterView, CardView card) {
- mCard = card;
- mClusterView = clusterView;
- }
-
- @Override
- public void run() {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "RemoveOrHideCard: " + mCard);
- }
-
- mClusterView.removeInvisibleDuplicatedCard(mCard);
-
- if (mCard.isGarbage()) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "RemoveOrHideCard, card has garbage priority");
- }
- mClusterView.removeCardInternal(mCard);
- } else {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "RemoveOrHideCard, hiding card: " + mCard);
- }
- mCard.setVisibility(GONE);
- mCard.setAlpha(1); // Restore alpha after fade-out animation, it's gone anyway.
- mClusterView.dumpCardsToLog();
- }
- }
- }
-
- private void removeCardInternal(CardView card) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "removeCardInternal, card: " + card);
- }
- mCardPanel.removeView(card);
- mQueue.remove(card);
-
- dumpCardsToLog();
- }
-
- @Override
- public void onPriorityChanged(CardView card, int priority) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "onPriorityChanged, card: " + card + ", priority: " + priority);
- }
- if (cardExists(card)) {
- enqueueCard(card);
- }
- }
-
- private void playRevealAnimation(final CardView cardToShow, final CardView currentCard,
- final Runnable oldCardDissapearedAction) {
-
- if (currentCard == cardToShow) {
- return;
- }
-
- if (currentCard != null) {
- playAlphaAnimation(currentCard,
- 0, // Target alpha
- 400, // Duration
- new DecelerateInterpolator(0.5f),
- oldCardDissapearedAction);
- }
-
- cardToShow.addOnLayoutChangeListener(new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- cardToShow.removeOnLayoutChangeListener(this); // Just need it once.
-
- createRevealAnimator(cardToShow, new DecelerateInterpolator(1f), true)
- .start();
- }
- });
- cardToShow.onPlayRevealAnimation();
- }
-
- private void playAlphaAnimation(final CardView card, float targetAlpha, long duration,
- Interpolator interpolator, final Runnable endAction) {
- Animation animation = new AlphaAnimation(card.getAlpha(), targetAlpha);
- animation.setDuration(duration * DebugUtil.ANIMATION_FACTOR);
- animation.setInterpolator(interpolator);
-
- animation.setAnimationListener(new AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) { }
-
- @Override
- public void onAnimationEnd(Animation animation) {
- // For some reason, cancelled animation hasEnded() == true here.
- // Check for start time instead.
- if (endAction != null && animation.getStartTime() != Long.MIN_VALUE) {
- endAction.run();
- }
- }
-
- @Override
- public void onAnimationRepeat(Animation animation) { }
- });
- card.setAnimation(animation);
- animation.start();
- }
-
- private static boolean isAnimationCancelled(Animation animation) {
- return (animation.getStartTime() == Long.MIN_VALUE) || (!animation.hasEnded());
- }
-
- private void playFadeOutAndSlideOutAnimation(final CardView card) {
- Animation animation = new TranslateAnimation(0, card.getWidth(), 0, 0) {
- private final float mFromAlpha = card.getAlpha();
- private final float mToAlpha = 0;
-
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- super.applyTransformation(interpolatedTime, t);
-
- final float alpha = mFromAlpha;
- t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
- }
- };
- animation.setDuration(600 * DebugUtil.ANIMATION_FACTOR);
- animation.setAnimationListener(new AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) { }
-
- @Override
- public void onAnimationEnd(Animation animation) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "playFadeOutAndSlideOutAnimation, onAnimationEnd " + animation
- + ", startTime: " + animation.getStartTime());
- }
- if (!isAnimationCancelled(animation)) {
- new RemoveOrHideCard(ClusterView.this, card)
- .run();
- }
- // Reset X position.
- card.setTranslationX(0);
- }
-
- @Override
- public void onAnimationRepeat(Animation animation) { }
- });
- card.setAnimation(animation);
- animation.start();
- }
-
- /** Hides given card and reveals underlying card */
- private void playUnrevealAnimation(final CardView card, final Runnable unrevealCompleteAction) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "playUnrevealAnimation, card: " + card);
- }
-
- final Animator anim = createRevealAnimator(card,
- new AccelerateInterpolator(2f), false /* hide */);
-
- anim.addListener(new AnimatorListenerAdapter() {
- private boolean cancelled = false;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "onAnimationCancel, animation: " + animation);
- }
- cancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (cancelled) {
- return;
- }
-
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "onAnimationEnd, animation: " + animation);
- }
- unrevealCompleteAction.run();
- }
- });
-
- anim.start();
- card.onPlayUnrevealAnimation();
- }
-
- private Animator createRevealAnimator(CardView card, Interpolator interpolator, boolean show) {
- int cardWidth = (int) getResources().getDimension(R.dimen.card_width);
- int radius = (int) (cardWidth * 1.2f);
- int centerY = (int) (getResources().getDimension(R.dimen.card_height) / 2);
-
- Animator anim = ViewAnimationUtils.createCircularReveal(card, radius, centerY,
- show ? 0 : radius /* start radius */,
- show ? radius : 0 /* end radius */);
-
- anim.setInterpolator(interpolator);
- anim.setDuration(600 * DebugUtil.ANIMATION_FACTOR);
- return anim;
- }
-
- public <E> E getCardOrNull(Class<E> clazz) {
- return mCardPanel.getChildOrNull(clazz);
- }
-
- public <E> E getVisibleCardOrNull(Class<E> clazz) {
- return mCardPanel.getVisibleChildOrNull(clazz);
- }
-
- private CallCard getCallCard() {
- return getCardOrNull(CallCard.class);
- }
-
- private void dumpCardsToLog() {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "Cards in layout: " + mCardPanel.getChildCount() + ", cards in queue: "
- + mQueue.size());
- for (int i = 0; i < mCardPanel.getChildCount(); i++) {
- Log.d(TAG, "child: " + mCardPanel.getChildAt(i));
- }
- }
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/DebugUtil.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/DebugUtil.java
deleted file mode 100644
index c42fe14..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/DebugUtil.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-/**
- * Utility functions / constants that make sense for debugging.
- */
-public final class DebugUtil {
- /** The default factor is 1, increasing this number results in slowing down animation */
- public static final long ANIMATION_FACTOR = 1;
-
- public static final String TAG = "CLUSTER";
-
- public static final boolean DEBUG = true;
-
- public static String getTag(Class clazz) {
- return TAG + "." + clazz.getSimpleName();
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/InstrumentClusterController.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/InstrumentClusterController.java
deleted file mode 100644
index fbfa8de..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/InstrumentClusterController.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.cluster.sample;
-
-import static com.android.car.cluster.sample.DebugUtil.DEBUG;
-
-import android.annotation.Nullable;
-import android.app.Presentation;
-import android.car.cluster.renderer.NavigationRenderer;
-import android.car.navigation.CarNavigationInstrumentCluster;
-import android.car.navigation.CarNavigationStatusManager;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.hardware.display.DisplayManager;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.session.PlaybackState;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.telecom.Call;
-import android.telecom.GatewayInfo;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Display;
-
-import com.android.car.cluster.sample.MediaStateMonitor.MediaStateListener;
-import com.android.car.cluster.sample.cards.MediaCard;
-import com.android.car.cluster.sample.cards.NavCard;
-
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.Timer;
-import java.util.TimerTask;
-
-/**
- * This class is responsible for subscribing to system events (such as call status, media status,
- * etc.) and updating accordingly UI component {@link ClusterView}.
- */
-/*package*/ class InstrumentClusterController {
-
- private final static String TAG = DebugUtil.getTag(InstrumentClusterController.class);
-
- private final Context mContext;
- private final NavigationRenderer mNavigationRenderer;
-
- private ClusterView mClusterView;
- private MediaStateMonitor mMediaStateMonitor;
- private MediaStateListenerImpl mMediaStateListener;
- private ClusterInCallService mInCallService;
- private MessagingNotificationHandler mNotificationHandler;
- private StatusBarNotificationListener mNotificationListener;
- private RetriableServiceBinder mInCallServiceRetriableBinder;
- private RetriableServiceBinder mNotificationServiceRetriableBinder;
-
- InstrumentClusterController(Context context) {
- mContext = context;
- mNavigationRenderer = new NavigationRendererImpl(this);
-
- init();
- }
-
- private void init() {
- grantNotificationListenerPermissionsIfNecessary(mContext);
-
- final Display display = getInstrumentClusterDisplay(mContext);
- if (DEBUG) {
- Log.d(TAG, "Instrument cluster display: " + display);
- }
- if (display == null) {
- return;
- }
-
- mClusterView = new ClusterView(mContext);
- Presentation presentation = new InstrumentClusterPresentation(mContext, display);
- presentation.setContentView(mClusterView);
-
- // To handle incoming messages
- mNotificationHandler = new MessagingNotificationHandler(mClusterView);
-
- mMediaStateListener = new MediaStateListenerImpl(this);
- mMediaStateMonitor = new MediaStateMonitor(mContext, mMediaStateListener);
-
- mInCallServiceRetriableBinder = new RetriableServiceBinder(
- new Handler(Looper.getMainLooper()),
- mContext,
- ClusterInCallService.class,
- ClusterInCallService.ACTION_LOCAL_BINDING,
- mInCallServiceConnection);
- mInCallServiceRetriableBinder.attemptToBind();
-
- mNotificationServiceRetriableBinder = new RetriableServiceBinder(
- new Handler(Looper.getMainLooper()),
- mContext,
- StatusBarNotificationListener.class,
- StatusBarNotificationListener.ACTION_LOCAL_BINDING,
- mNotificationListenerConnection);
- mNotificationServiceRetriableBinder.attemptToBind();
-
- // Show default card - weather
- mClusterView.enqueueCard(mClusterView.createWeatherCard());
-
- presentation.show();
- }
-
- NavigationRenderer getNavigationRenderer() {
- return mNavigationRenderer;
- }
-
- private final ServiceConnection mInCallServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- if (DEBUG) {
- Log.d(TAG, "onServiceConnected, name: " + name + ", binder: " + binder);
- }
-
- mInCallService = ((ClusterInCallService.LocalBinder) binder).getService();
- mInCallService.registerListener(mCallServiceListener);
-
- // The InCallServiceImpl could be bound when we already have some active calls, let's
- // notify UI about these calls.
- for (Call call : mInCallService.getCalls()) {
- mCallServiceListener.onStateChanged(call, call.getState());
- }
- mInCallServiceRetriableBinder = null;
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) {
- Log.d(TAG, "onServiceDisconnected, name: " + name);
- }
- }
- };
-
- private final ServiceConnection mNotificationListenerConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- if (DEBUG) {
- Log.d(TAG, "onServiceConnected, name: " + name + ", binder: " + binder);
- }
-
- mNotificationListener = ((StatusBarNotificationListener.LocalBinder) binder)
- .getService();
- mNotificationListener.setHandler(mNotificationHandler);
-
- mNotificationServiceRetriableBinder = null;
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) {
- Log.d(TAG, "onServiceDisconnected, name: "+ name);
- }
- }
- };
-
- private final Call.Callback mCallServiceListener = new Call.Callback() {
- @Override
- public void onStateChanged(Call call, int state) {
- if (DEBUG) {
- Log.d(TAG, "onCallStateChanged, call: " + call + ", state: " + state);
- }
-
- runOnMain(() -> InstrumentClusterController.this.onCallStateChanged(call, state));
- }
- };
-
- private String extractPhoneNumber(Call call) {
- String number = "";
- Call.Details details = call.getDetails();
- if (details != null) {
- GatewayInfo gatewayInfo = details.getGatewayInfo();
-
- if (gatewayInfo != null) {
- number = gatewayInfo.getOriginalAddress().getSchemeSpecificPart();
- } else if (details.getHandle() != null) {
- number = details.getHandle().getSchemeSpecificPart();
- }
- } else {
- number = mContext.getResources().getString(R.string.unknown);
- }
-
- return number;
- }
-
- private void onCallStateChanged(Call call, int state) {
- if (DEBUG) {
- Log.d(TAG, "onCallStateChanged, call: " + call + ", state: " + state);
- }
-
- switch (state) {
- case Call.STATE_ACTIVE: {
- Call.Details details = call.getDetails();
- if (details != null) {
- long duration = System.currentTimeMillis() - details.getConnectTimeMillis();
- mClusterView.handleCallConnected(SystemClock.elapsedRealtime() - duration);
- }
- } break;
- case Call.STATE_CONNECTING: {
-
- } break;
- case Call.STATE_DISCONNECTING: {
- mClusterView.handleCallDisconnected();
- } break;
- case Call.STATE_DIALING: {
- String phoneNumber = extractPhoneNumber(call);
- String displayName = TelecomUtils.getDisplayName(mContext, phoneNumber);
- Bitmap image = TelecomUtils
- .getContactPhotoFromNumber(mContext.getContentResolver(), phoneNumber);
- mClusterView.handleDialingCall(image, displayName);
- } break;
- case Call.STATE_DISCONNECTED: {
- mClusterView.handleCallDisconnected();
- } break;
- case Call.STATE_HOLDING:
- break;
- case Call.STATE_NEW:
- break;
- case Call.STATE_RINGING: {
- String phoneNumber = extractPhoneNumber(call);
- String displayName = TelecomUtils.getDisplayName(mContext, phoneNumber);
- Bitmap image = TelecomUtils
- .getContactPhotoFromNumber(mContext.getContentResolver(), phoneNumber);
- if (image != null) {
- if (DEBUG) {
- Log.d(TAG, "Incoming call, contact image size: " + image.getWidth()
- + "x" + image.getHeight());
- }
- }
- mClusterView.handleIncomingCall(image, displayName);
- } break;
- default:
- Log.w(TAG, "Unexpected call state: " + state + ", call : " + call);
- }
- }
-
- private static void grantNotificationListenerPermissionsIfNecessary(Context context) {
- ComponentName componentName = new ComponentName(context,
- StatusBarNotificationListener.class);
- String componentFlatten = componentName.flattenToString();
-
- ContentResolver resolver = context.getContentResolver();
- String grantedComponents = Settings.Secure.getString(resolver,
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-
- if (grantedComponents != null) {
- String[] allowed = grantedComponents.split(":");
- for (String s : allowed) {
- if (s.equals(componentFlatten)) {
- if (DEBUG) {
- Log.d(TAG, "Notification listener permission granted.");
- }
- return; // Permission already granted.
- }
- }
- }
-
- if (DEBUG) {
- Log.d(TAG, "Granting notification listener permission.");
- }
- Settings.Secure.putString(resolver,
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- grantedComponents + ":" + componentFlatten);
-
- }
-
- /* package */ void onDestroy() {
- if (mMediaStateMonitor != null) {
- mMediaStateMonitor.release();
- mMediaStateMonitor = null;
- }
- if (mMediaStateListener != null) {
- mMediaStateListener.release();
- mMediaStateListener = null;
- }
- if (mInCallService != null) {
- mContext.unbindService(mInCallServiceConnection);
- mInCallService = null;
- }
- if (mNotificationListener != null) {
- mContext.unbindService(mNotificationListenerConnection);
- mNotificationListener = null;
- }
- if (mInCallServiceRetriableBinder != null) {
- mInCallServiceRetriableBinder.release();
- mInCallServiceRetriableBinder = null;
- }
- if (mNotificationServiceRetriableBinder != null) {
- mNotificationServiceRetriableBinder.release();
- mNotificationServiceRetriableBinder = null;
- }
- }
-
- private static Display getInstrumentClusterDisplay(Context context) {
- DisplayManager displayManager = context.getSystemService(DisplayManager.class);
- Display[] displays = displayManager.getDisplays();
-
- if (DEBUG) {
- Log.d(TAG, "There are currently " + displays.length + " displays connected.");
- for (Display display : displays) {
- Log.d(TAG, " " + display);
- }
- }
-
- if (displays.length > 1) {
- // TODO: Put this into settings?
- return displays[displays.length - 1];
- }
- return null;
- }
-
- private static void runOnMain(Runnable runnable) {
- new Handler(Looper.getMainLooper()).post(runnable);
- }
-
- private static class MediaStateListenerImpl implements MediaStateListener {
- private final Timer mTimer = new Timer("ClusterMediaProgress");
- private final ClusterView mClusterView;
-
- private MediaData mCurrentMedia;
- private MediaAppInfo mMediaAppInfo;
- private MediaCard mCard;
- private PlaybackState mPlaybackState;
- private TimerTask mTimerTask;
-
- MediaStateListenerImpl(InstrumentClusterController renderer) {
- mClusterView = renderer.mClusterView;
- }
-
- void release() {
- if (mTimerTask != null) {
- mTimerTask.cancel();
- mTimerTask = null;
- }
- }
-
- @Override
- public void onPlaybackStateChanged(final PlaybackState playbackState) {
- if (DEBUG) {
- Log.d(TAG, "onPlaybackStateChanged, playbackState: " + playbackState);
- }
-
- if (mTimerTask != null) {
- mTimerTask.cancel();
- mTimerTask = null;
- }
-
- if (playbackState != null) {
- if ((playbackState.getState() == PlaybackState.STATE_PLAYING
- || playbackState.getState() == PlaybackState.STATE_BUFFERING)) {
- mPlaybackState = playbackState;
-
- if (mCurrentMedia != null) {
- showMediaCardIfNecessary(mCurrentMedia);
-
- if (mCurrentMedia.duration > 0) {
- startTrackProgressTimer();
- }
- }
- } else if (playbackState.getState() == PlaybackState.STATE_STOPPED
- || playbackState.getState() == PlaybackState.STATE_ERROR
- || playbackState.getState() == PlaybackState.STATE_NONE) {
- hideMediaCard();
- }
- } else {
- hideMediaCard();
- }
-
- }
-
- private void startTrackProgressTimer() {
- mTimerTask = new TimerTask() {
- @Override
- public void run() {
- runOnMain(() -> {
- if (mPlaybackState == null || mCard == null) {
- return;
- }
- long trackStarted = mPlaybackState.getLastPositionUpdateTime()
- - mPlaybackState.getPosition();
- long trackDuration = mCurrentMedia == null ? 0 : mCurrentMedia.duration;
-
- long currentTime = SystemClock.elapsedRealtime();
- long progressMs = (currentTime - trackStarted);
- if (trackDuration > 0) {
- mCard.setProgress((int)((progressMs * 100) / trackDuration));
- }
- });
- }
- };
-
- mTimer.scheduleAtFixedRate(mTimerTask, 0, 1000);
- }
-
-
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- if (DEBUG) {
- Log.d(TAG, "onMetadataChanged: " + metadata);
- }
- MediaData data = MediaData.createFromMetadata(metadata);
- if (data == null) {
- hideMediaCard();
- }
- mCurrentMedia = data;
- }
-
- private void hideMediaCard() {
- if (DEBUG) {
- Log.d(TAG, "hideMediaCard");
- }
-
- if (mCard != null) {
- mClusterView.removeCard(mCard);
- mCard = null;
- }
-
- // Remove all existing media cards if any.
- MediaCard mediaCard;
- do {
- mediaCard = mClusterView.getCardOrNull(MediaCard.class);
- if (mediaCard != null) {
- mClusterView.removeCard(mediaCard);
- }
- } while (mediaCard != null);
- }
-
- private void showMediaCardIfNecessary(MediaData data) {
- if (!needToCreateMediaCard(data)) {
- return;
- }
-
- int accentColor = mMediaAppInfo == null
- ? Color.GRAY : mMediaAppInfo.getMediaClientAccentColor();
-
- mCard = mClusterView.createMediaCard(
- data.albumCover, data.title, data.subtitle, accentColor);
- if (data.duration <= 0) {
- mCard.setProgress(100); // unknown position
- } else {
- mCard.setProgress(0);
- }
- mClusterView.enqueueCard(mCard);
- }
-
- private boolean needToCreateMediaCard(MediaData data) {
- return (mCard == null)
- || !Objects.equals(mCard.getTitle(), data.title)
- || !Objects.equals(mCard.getSubtitle(), data.subtitle);
- }
-
- @Override
- public void onMediaAppChanged(MediaAppInfo mediaAppInfo) {
- mMediaAppInfo = mediaAppInfo;
- }
-
- private static class MediaData {
- final Bitmap albumCover;
- final String subtitle;
- final String title;
- final long duration;
-
- private MediaData(MediaMetadata metadata) {
- MediaDescription mediaDescription = metadata.getDescription();
- title = charSequenceToString(mediaDescription.getTitle());
- subtitle = charSequenceToString(mediaDescription.getSubtitle());
- albumCover = mediaDescription.getIconBitmap();
- duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
- }
-
- static MediaData createFromMetadata(MediaMetadata metadata) {
- return metadata == null ? null : new MediaData(metadata);
- }
-
- private static String charSequenceToString(@Nullable CharSequence cs) {
- return cs == null ? null : String.valueOf(cs);
- }
-
- @Override
- public String toString() {
- return "MediaData{" +
- "albumCover=" + albumCover +
- ", subtitle='" + subtitle + '\'' +
- ", title='" + title + '\'' +
- ", duration=" + duration +
- '}';
- }
- }
- }
-
- private static class NavigationRendererImpl extends NavigationRenderer {
-
- private final InstrumentClusterController mController;
-
- private ClusterView mClusterView;
- private Resources mResources;
-
- private NavCard mNavCard;
-
- NavigationRendererImpl(InstrumentClusterController controller) {
- mController = controller;
- }
-
- @Override
- public CarNavigationInstrumentCluster getNavigationProperties() {
- if (DEBUG) {
- Log.d(TAG, "getNavigationProperties");
- }
- return CarNavigationInstrumentCluster.createCustomImageCluster(
- 1000, /* 1 Hz*/
- 64, /* image width */
- 64, /* image height */
- 32); /* color depth */
- }
-
- @Override
- public void onEvent(int eventType, Bundle bundle) {
- if (DEBUG) {
- Log.d(TAG, "onEvent");
- }
- // Implement this.
- }
- }
-
- /**
- * Services might not be ready for binding. This class will retry binding after short interval
- * if previous binding failed.
- */
- private static class RetriableServiceBinder {
- private static final long RETRY_INTERVAL_MS = 500;
- private static final long MAX_RETRY = 30;
-
- private Handler mHandler;
- private final Context mContext;
- private final Intent mIntent;
- private final ServiceConnection mConnection;
-
- private long mAttemptsLeft = MAX_RETRY;
-
- private final Runnable mBindRunnable = () -> attemptToBind();
-
- RetriableServiceBinder(Handler handler, Context context, Class<?> cls, String action,
- ServiceConnection connection) {
- mHandler = handler;
- mContext = context;
- mIntent = new Intent(mContext, cls);
- mIntent.setAction(action);
- mConnection = connection;
- }
-
- void release() {
- mHandler.removeCallbacks(mBindRunnable);
- }
-
- void attemptToBind() {
- boolean bound = mContext.bindServiceAsUser(mIntent,
- mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF);
-
- if (!bound && --mAttemptsLeft > 0) {
- mHandler.postDelayed(mBindRunnable, RETRY_INTERVAL_MS);
- } else if (!bound) {
- Log.e(TAG, "Gave up to bind to a service: " + mIntent.getComponent() + " after "
- + MAX_RETRY + " retries.");
- }
- }
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/InstrumentClusterPresentation.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/InstrumentClusterPresentation.java
deleted file mode 100644
index 3a3068e..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/InstrumentClusterPresentation.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.cluster.sample;
-
-import android.app.Presentation;
-import android.content.Context;
-import android.view.Display;
-import android.view.WindowManager;
-
-/**
- * Presentation class.
- */
-public class InstrumentClusterPresentation extends Presentation {
- public InstrumentClusterPresentation(Context outerContext, Display display) {
- super(outerContext, display);
- // To allow presentation from the service.
- getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/InstrumentClusterRenderingServiceImpl.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/InstrumentClusterRenderingServiceImpl.java
deleted file mode 100644
index 066072e..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/InstrumentClusterRenderingServiceImpl.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-import android.car.cluster.renderer.InstrumentClusterRenderingService;
-import android.car.cluster.renderer.NavigationRenderer;
-import android.view.KeyEvent;
-
-/**
- * Service for {@link InstrumentClusterController}. This is entry-point of the instrument cluster
- * renderer. This service will be bound from Car Service.
- */
-public class InstrumentClusterRenderingServiceImpl extends InstrumentClusterRenderingService {
-
- private InstrumentClusterController mController;
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- mController = new InstrumentClusterController(this /* context */);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (mController != null) {
- mController.onDestroy();
- mController = null;
- }
- }
-
- @Override
- public NavigationRenderer getNavigationRenderer() {
- return mController.getNavigationRenderer();
- }
-
- @Override
- public void onKeyEvent(KeyEvent keyEvent) {
- // No need to handle key events in this implementation.
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/ManeuverPanel.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/ManeuverPanel.java
deleted file mode 100644
index 835b9ed..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/ManeuverPanel.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import com.android.car.cluster.sample.cards.NavCard;
-
-/**
- * Contains text information about next maneuver. This panel is used in {@link NavCard}.
- */
-public class ManeuverPanel extends FrameLayout {
-
- private TextView mDistance;
- private TextView mDistanceUnits;
- private TextView mStreet;
-
- public ManeuverPanel(Context context) {
- this(context, null);
- }
-
- public ManeuverPanel(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- inflate(context, R.layout.nav_card_maneuver_description, this);
-
- mDistance = (TextView) findViewById(R.id.nav_distance);
- mDistanceUnits = (TextView) findViewById(R.id.nav_distance_units);
- mStreet = (TextView) findViewById(R.id.nav_street);
- }
-
- public void setDistanceToNextManeuver(String distance, String units) {
- mDistance.setText(distance);
- mDistanceUnits.setText(units);
- }
-
- public void setStreet(CharSequence street) {
- mStreet.setText(street);
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MediaAppInfo.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MediaAppInfo.java
deleted file mode 100644
index 3f1e004..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MediaAppInfo.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.cluster.sample;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.util.Log;
-
-/**
- * An immutable class which hold the the information about the currently connected media app.
- */
-public class MediaAppInfo {
- private static final String TAG = DebugUtil.getTag(MediaAppInfo.class);
-
- private int mAccentColor;
-
- public MediaAppInfo(Context context, String packageName) {
- try {
- PackageManager packageManager = context.getPackageManager();
- ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName,
- PackageManager.GET_META_DATA);
-
- fetchAppColors(packageName, appInfo.theme, context);
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Got a component that doesn't exist (" + packageName + ")");
- }
- }
-
- public int getMediaClientAccentColor() {
- return mAccentColor;
- }
-
- private void fetchAppColors(String packageName, int appTheme, Context context) {
- TypedArray ta = null;
- try {
- Context packageContext = context.createPackageContext(packageName, 0);
- packageContext.setTheme(appTheme);
- Resources.Theme theme = packageContext.getTheme();
- ta = theme.obtainStyledAttributes(new int[]{ android.R.attr.colorAccent });
- mAccentColor = ta.getColor(1,
- context.getResources().getColor(android.R.color.holo_green_light));
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Unable to update media client package attributes.", e);
- } finally {
- if (ta != null) {
- ta.recycle();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MediaStateMonitor.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MediaStateMonitor.java
deleted file mode 100644
index 2b68d07..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MediaStateMonitor.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.cluster.sample;
-
-import static com.android.car.cluster.sample.DebugUtil.DEBUG;
-
-import android.content.Context;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
-import android.media.session.PlaybackState;
-import android.util.Log;
-
-import java.lang.ref.WeakReference;
-import java.util.List;
-
-/**
- * Reports current media status to instrument cluster renderer through {@link MediaStateListener}
- */
-public class MediaStateMonitor {
-
- private final static String TAG = DebugUtil.getTag(MediaStateMonitor.class);
-
- private final Context mContext;
- private final MediaListener mMediaListener;
- private MediaController mPrimaryMediaController;
- private OnActiveSessionsChangedListener mActiveSessionsChangedListener;
- private MediaSessionManager mMediaSessionManager;
- private MediaStateListener mListener;
-
- public MediaStateMonitor(Context context, MediaStateListener listener) {
- mListener = listener;
- mContext = context;
- mMediaListener = new MediaListener(this);
- mActiveSessionsChangedListener = controllers -> onActiveSessionsChanged(controllers);
- mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
- mMediaSessionManager.addOnActiveSessionsChangedListener(
- mActiveSessionsChangedListener, null);
-
- onActiveSessionsChanged(mMediaSessionManager.getActiveSessions(null));
- }
-
- private void onActiveSessionsChanged(List<MediaController> controllers) {
- if (DEBUG) {
- Log.d(TAG, "onActiveSessionsChanged, controllers found: " + controllers.size());
- }
- MediaController newPrimaryController = null;
- if (!controllers.isEmpty()) {
- newPrimaryController = controllers.get(0);
- if (mPrimaryMediaController == newPrimaryController) {
- // Primary media controller has not been changed.
- return;
- }
- }
-
- releasePrimaryMediaController();
-
- if (newPrimaryController != null) {
- mPrimaryMediaController = newPrimaryController;
- mPrimaryMediaController.registerCallback(mMediaListener);
- mListener.onMediaAppChanged(
- new MediaAppInfo(mContext, mPrimaryMediaController.getPackageName()));
- }
- updateRendererMediaStatusIfAvailable();
- }
-
- public void release() {
- releasePrimaryMediaController();
- if (mActiveSessionsChangedListener != null) {
- mMediaSessionManager.removeOnActiveSessionsChangedListener(
- mActiveSessionsChangedListener);
- mActiveSessionsChangedListener = null;
- }
- mMediaSessionManager = null;
- }
-
- private void releasePrimaryMediaController() {
- if (mPrimaryMediaController != null) {
- mPrimaryMediaController.unregisterCallback(mMediaListener);
- mPrimaryMediaController = null;
- }
- }
-
- private void updateRendererMediaStatusIfAvailable() {
- mListener.onMetadataChanged(
- mPrimaryMediaController == null ? null : mPrimaryMediaController.getMetadata());
- mListener.onPlaybackStateChanged(
- mPrimaryMediaController == null
- ? null : mPrimaryMediaController.getPlaybackState());
- }
-
- private void onPlaybackStateChanged(PlaybackState state) {
- mListener.onPlaybackStateChanged(state);
- }
-
- private void onMetadataChanged(MediaMetadata metadata) {
- mListener.onMetadataChanged(metadata);
- }
-
- public interface MediaStateListener {
- void onPlaybackStateChanged(PlaybackState playbackState);
- void onMetadataChanged(MediaMetadata metadata);
- void onMediaAppChanged(MediaAppInfo mediaAppPackage);
- }
-
- private static class MediaListener extends MediaController.Callback {
- private final WeakReference<MediaStateMonitor> mServiceRef;
-
- MediaListener(MediaStateMonitor service) {
- mServiceRef = new WeakReference<>(service);
- }
-
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- MediaStateMonitor service = mServiceRef.get();
- if (service != null) {
- service.onPlaybackStateChanged(state);
- }
- }
-
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- MediaStateMonitor service = mServiceRef.get();
- if (service != null) {
- service.onMetadataChanged(metadata);
- }
- }
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MessagingConverter.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MessagingConverter.java
deleted file mode 100644
index eddeec7..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MessagingConverter.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-import android.app.Notification;
-import android.graphics.Bitmap;
-import android.service.notification.StatusBarNotification;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.core.app.NotificationCompat.CarExtender;
-import androidx.core.app.NotificationCompat.CarExtender.UnreadConversation;
-
-/**
- * Convert a {@link CarExtender} notification into a {@link MessageContactDetails}
- */
-public class MessagingConverter {
- private static final String TAG = DebugUtil.getTag(MessagingConverter.class);
-
- public static boolean canConvert(StatusBarNotification sbn) {
- Notification notification = sbn.getNotification();
- if (notification == null) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "Notification is empty.");
- }
- return false;
- }
- CarExtender ce = new CarExtender(sbn.getNotification());
- if (ce.getUnreadConversation() == null) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "Notification with no messaging component.");
- }
- return false;
- }
-
- CarExtender.UnreadConversation uc = ce.getUnreadConversation();
- String[] messages = uc.getMessages();
- if (messages == null || messages.length == 0) {
- Log.w(TAG, "Car message notification with no messages.");
- return false;
- }
-
- if (TextUtils.isEmpty(uc.getParticipant())) {
- Log.w(TAG, "Car message notification with no participant.");
- return false;
- }
-
- if (uc.getReplyPendingIntent() == null) {
- Log.w(TAG, "Car message notification with no reply intent.");
- return false;
- }
-
- for (String m : messages) {
- if (m == null) {
- Log.w(TAG, "Car message with null text.");
- return false;
- }
- }
- return true;
- }
-
- public static MessageContactDetails convert(StatusBarNotification sbn) {
- CarExtender ce = new CarExtender(sbn.getNotification());
- UnreadConversation uc = ce.getUnreadConversation();
-
- Bitmap largeIcon = ce.getLargeIcon();
- if (largeIcon == null) {
- largeIcon = sbn.getNotification().largeIcon;
- }
- String name = uc.getParticipant();
-
- return new MessageContactDetails(largeIcon, name);
- }
-
- public static class MessageContactDetails {
- private final Bitmap mContactImage;
- private final String mContactName;
-
- private MessageContactDetails(Bitmap contactImage, String contactName) {
- mContactImage = contactImage;
- mContactName = contactName;
- }
-
- public Bitmap getContactImage() {
- return mContactImage;
- }
-
- public String getContactName() {
- return mContactName;
- }
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MessagingNotificationHandler.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MessagingNotificationHandler.java
deleted file mode 100644
index e88ee46..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/MessagingNotificationHandler.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-import static com.android.car.cluster.sample.DebugUtil.DEBUG;
-
-import android.app.Notification;
-import android.os.Handler;
-import android.os.Message;
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-
-import com.android.car.cluster.sample.MessagingConverter.MessageContactDetails;
-
-/**
- * Handles messaging {@link StatusBarNotification}.
- */
-class MessagingNotificationHandler extends Handler {
- private static final String TAG = DebugUtil.getTag(MessagingNotificationHandler.class);
-
- private final ClusterView mClusterView;
-
- MessagingNotificationHandler(ClusterView cluster) {
- mClusterView = cluster;
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (DEBUG) {
- Log.d(TAG, "NotificationHandler, handleMessage: " + msg);
- }
- if (msg.obj instanceof StatusBarNotification) {
- StatusBarNotification sbn = (StatusBarNotification) msg.obj;
- Notification notification = sbn.getNotification();
- if (notification != null) {
- if (DEBUG) {
- Log.d(TAG, "NotificationHandler, notification extras: "
- + notification.extras.toString());
- }
- if (MessagingConverter.canConvert(sbn)) {
- MessageContactDetails data = MessagingConverter.convert(sbn);
- mClusterView.handleHangoutMessage(
- data.getContactImage(), data.getContactName());
- } else {
- Log.w(TAG, "Can't convert message: " + sbn);
- }
- }
- } else {
- Log.w(TAG, "Unexpected message with object: " + msg.obj);
- }
- }
-}
\ No newline at end of file
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/StatusBarNotificationListener.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/StatusBarNotificationListener.java
deleted file mode 100644
index 8758766..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/StatusBarNotificationListener.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-import android.content.Intent;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-
-/**
- * Listens to status bar notifications and passes it to the listener.
- */
-public class StatusBarNotificationListener extends NotificationListenerService {
-
- private static final String TAG = DebugUtil.getTag(StatusBarNotificationListener.class);
-
- static final String ACTION_LOCAL_BINDING = "local_binding";
-
- private Handler mHandler;
-
- @Override
- public void onNotificationPosted(StatusBarNotification sbn) {
- if (MessagingConverter.canConvert(sbn) && mHandler != null) {
- Message msg = Message.obtain(mHandler);
- msg.obj = sbn;
- mHandler.sendMessage(msg);
- }
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- Log.d(TAG, "onBind, intent:" + intent);
-
- return ACTION_LOCAL_BINDING.equals(intent.getAction())
- ? new LocalBinder() : super.onBind(intent);
- }
-
- public void setHandler(Handler handler) {
- mHandler = handler;
- }
-
- public class LocalBinder extends Binder {
- public StatusBarNotificationListener getService() {
- return StatusBarNotificationListener.this;
- }
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/TelecomUtils.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/TelecomUtils.java
deleted file mode 100644
index dfe7cb7..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/TelecomUtils.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample;
-
-/**
- * Utility class to retrieve contact information.
- */
-import android.annotation.Nullable;
-import android.annotation.WorkerThread;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapFactory.Options;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.provider.ContactsContract;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.LruCache;
-
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Locale;
-
-public class TelecomUtils {
-
- private final static String TAG = DebugUtil.getTag(TelecomUtils.class);
-
- private static final String[] CONTACT_ID_PROJECTION = new String[] {
- ContactsContract.PhoneLookup.DISPLAY_NAME,
- ContactsContract.PhoneLookup.TYPE,
- ContactsContract.PhoneLookup.LABEL,
- ContactsContract.PhoneLookup._ID
- };
-
- private static LruCache<String, Bitmap> sContactPhotoNumberCache;
- private static LruCache<Long, Bitmap> sContactPhotoIdCache;
- private static HashMap<String, Integer> sContactIdCache;
- private static HashMap<String, String> sFormattedNumberCache;
- private static HashMap<String, String> sDisplayNameCache;
- private static HashMap<String, String> sContactNameCache;
- private static String sVoicemailNumber;
- private static TelephonyManager sTelephonyManager;
-
- /**
- * Fetch contact photo by number from local cache.
- *
- * @param number
- * @return Contact photo if it's in the cache, otherwise null.
- */
- @Nullable
- public static Bitmap getCachedContactPhotoFromNumber(String number) {
- if (number == null) {
- return null;
- }
-
- if (sContactPhotoNumberCache == null) {
- sContactPhotoNumberCache = new LruCache<String, Bitmap>(4194304 /** 4 mb **/) {
- @Override
- protected int sizeOf(String key, Bitmap value) {
- return value.getByteCount();
- }
- };
- } else if (sContactPhotoNumberCache.get(number) != null) {
- return sContactPhotoNumberCache.get(number);
- }
-
- return null;
- }
-
- @WorkerThread
- public static Bitmap getContactPhotoFromNumber(ContentResolver contentResolver, String number) {
- if (number == null) {
- return null;
- }
-
- Bitmap photo = getCachedContactPhotoFromNumber(number);
- if (photo != null) {
- return photo;
- }
-
- int id = getContactIdFromNumber(contentResolver, number);
- if (id == 0) {
- return null;
- }
- photo = getContactPhotoFromId(contentResolver, id);
- if (photo != null) {
- sContactPhotoNumberCache.put(number, photo);
- }
- return photo;
- }
-
- /**
- * Return the contact id for the given contact id
- * @param id the contact id to get the photo for
- * @return the contact photo if it is found, null otherwise.
- */
- public static Bitmap getContactPhotoFromId(ContentResolver contentResolver, long id) {
- if (sContactPhotoIdCache == null) {
- sContactPhotoIdCache = new LruCache<Long, Bitmap>(4194304 /** 4 mb **/) {
- @Override
- protected int sizeOf(Long key, Bitmap value) {
- return value.getByteCount();
- }
- };
- } else if (sContactPhotoIdCache.get(id) != null) {
- return sContactPhotoIdCache.get(id);
- }
-
- Uri photoUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
- InputStream photoDataStream = ContactsContract.Contacts.openContactPhotoInputStream(
- contentResolver, photoUri, true);
-
- Options options = new Options();
- options.inPreferQualityOverSpeed = true;
- // Scaling will be handled by later. We shouldn't scale multiple times to avoid
- // quality lost due to multiple potential scaling up and down.
- options.inScaled = false;
-
- Rect nullPadding = null;
- Bitmap photo = BitmapFactory.decodeStream(photoDataStream, nullPadding, options);
- if (photo != null) {
- photo.setDensity(Bitmap.DENSITY_NONE);
- sContactPhotoIdCache.put(id, photo);
- }
- return photo;
- }
-
- /**
- * Return the contact id for the given phone number.
- * @param number Caller phone number
- * @return the contact id if it is found, 0 otherwise.
- */
- public static int getContactIdFromNumber(ContentResolver cr, String number) {
- if (number == null || number.isEmpty()) {
- return 0;
- }
- if (sContactIdCache == null) {
- sContactIdCache = new HashMap<>();
- } else if (sContactIdCache.containsKey(number)) {
- return sContactIdCache.get(number);
- }
-
-
- Uri uri = Uri.withAppendedPath(
- ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
- Uri.encode(number));
- Cursor cursor = cr.query(uri, CONTACT_ID_PROJECTION, null, null, null);
-
- try {
- if (cursor != null && cursor.moveToFirst()) {
- int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID));
- sContactIdCache.put(number, id);
- return id;
- }
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return 0;
- }
-
- public static String getVoicemailNumber(Context context) {
- if (sVoicemailNumber == null) {
- sVoicemailNumber = getTelephonyManager(context).getVoiceMailNumber();
- }
- return sVoicemailNumber;
- }
-
- public static TelephonyManager getTelephonyManager(Context context) {
- if (sTelephonyManager == null) {
- sTelephonyManager =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- }
- return sTelephonyManager;
- }
-
- public static String getFormattedNumber(Context context, String number) {
- Log.d(TAG, "getFormattedNumber: " + number);
- if (number == null) {
- return "";
- }
-
- if (sFormattedNumberCache == null) {
- sFormattedNumberCache = new HashMap<>();
- } else {
- if (sFormattedNumberCache.containsKey(number)) {
- return sFormattedNumberCache.get(number);
- }
- }
-
- String countryIso = getTelephonyManager(context).getSimCountryIso().toUpperCase(Locale.US);
- if (countryIso.length() != 2) {
- countryIso = Locale.getDefault().getCountry();
- if (countryIso == null || countryIso.length() != 2) {
- countryIso = "US";
- }
- }
- Log.d(TAG, "PhoneNumberUtils.formatNumberToE16, number: "
- + number + ", country: " + countryIso);
- String e164 = PhoneNumberUtils.formatNumberToE164(number, countryIso);
- String formattedNumber = PhoneNumberUtils.formatNumber(number, e164, countryIso);
- formattedNumber = TextUtils.isEmpty(formattedNumber) ? number : formattedNumber;
- sFormattedNumberCache.put(number, formattedNumber);
- Log.d(TAG, "getFormattedNumber, result: " + formattedNumber);
- return formattedNumber;
- }
-
- public static String getDisplayName(Context context, String number) {
- return getDisplayName(context, number, null);
- }
-
- private static String getDisplayName(Context context, String number, Uri gatewayOriginalAddress) {
- Log.d(TAG, "getDisplayName: " + number
- + ", gatewayOriginalAddress: " + gatewayOriginalAddress);
- if (sDisplayNameCache == null) {
- sDisplayNameCache = new HashMap<>();
- } else {
- if (sDisplayNameCache.containsKey(number)) {
- return sDisplayNameCache.get(number);
- }
- }
-
- if (TextUtils.isEmpty(number)) {
- return context.getString(R.string.unknown);
- }
- ContentResolver cr = context.getContentResolver();
- String name;
- if (number.equals(getVoicemailNumber(context))) {
- name = context.getResources().getString(R.string.voicemail);
- } else {
- name = getContactNameFromNumber(cr, number);
- }
-
- if (name == null) {
- name = getFormattedNumber(context, number);
- }
- if (name == null && gatewayOriginalAddress != null) {
- name = gatewayOriginalAddress.getSchemeSpecificPart();
- }
- if (name == null) {
- name = context.getString(R.string.unknown);
- }
- sDisplayNameCache.put(number, name);
- return name;
- }
-
- private static String getContactNameFromNumber(ContentResolver cr, String number) {
- if (sContactNameCache == null) {
- sContactNameCache = new HashMap<>();
- } else if (sContactNameCache.containsKey(number)) {
- return sContactNameCache.get(number);
- }
-
- Uri uri = Uri.withAppendedPath(
- ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
-
- Cursor cursor = null;
- String name = null;
- try {
- cursor = cr.query(uri,
- new String[] {ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
- if (cursor != null && cursor.moveToFirst()) {
- name = cursor.getString(0);
- sContactNameCache.put(number, name);
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return name;
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/CallCard.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/CallCard.java
deleted file mode 100644
index 4ca58e6..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/CallCard.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample.cards;
-
-import android.animation.TimeInterpolator;
-import android.content.Context;
-import android.graphics.BitmapFactory;
-import android.util.Log;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.Chronometer;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.car.cluster.sample.DebugUtil;
-import com.android.car.cluster.sample.R;
-
-/**
- * Card responsible to display current call status.
- */
-public class CallCard extends CardView {
-
- private final static String TAG = DebugUtil.getTag(CallCard.class);
-
- private LinearLayout mPhonePanel;
- private Chronometer mCallDuration;
- private TextView mContactName;
- private TextView mCallStatusTextView;
- private LinearLayout mCallDurationPanel;
-
- private int mIncomingCallTextHeight;
- private int mCallDurationTextHeight;
-
- public int getCallStatus() {
- return mCallStatus;
- }
-
- public @interface CallStatus {
- int INCOMING_OR_DIALING = 1;
- int ACTIVE = 2;
- int DISCONNECTED = 4;
- }
-
- @CallStatus
- private int mCallStatus;
-
- public CallCard(Context context, PriorityChangedListener listener) {
- super(context, CardType.PHONE_CALL, listener);
- }
-
- @Override
- protected void init() {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "init");
- }
- mCallStatus = CallStatus.INCOMING_OR_DIALING;
- mPriority = PRIORITY_CALL_INCOMING;
-
- inflate(R.layout.call_card);
-
- mPhonePanel = viewById(R.id.phone_text_panel);
- mCallStatusTextView = viewById(R.id.call_status);
- mCallDuration = viewById(R.id.call_duration);
- mContactName = viewById(R.id.contact_name);
- mCallDurationPanel = viewById(R.id.call_duration_panel);
- mDetailsPanel = mPhonePanel;
-
- mLeftIconSwitcher.setVisibility(GONE);
- mCallDurationPanel.setVisibility(INVISIBLE);
-
- setRightIcon(
- BitmapFactory.decodeResource(getResources(), R.drawable.phone), true);
-
- final ViewTreeObserver observer = mPhonePanel.getViewTreeObserver();
- // Make sure to get dimensions after layout has been created.
- observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- mPhonePanel.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- mIncomingCallTextHeight = mCallStatusTextView.getHeight();
- mCallDurationTextHeight = mCallDuration.getHeight();
-
- // Call duration is hidden when call is not answered, adjust panel Y pos.
- mPhonePanel.setTranslationY(mCallDurationTextHeight / 2);
- }
- });
- }
-
- public void setContactName(String contactName) {
- mContactName.setText(contactName);
- }
-
- public void setStatusLabel(String status) {
- mCallStatusTextView.setText(status);
- }
-
- public void animateCallConnected(long connectedTimestamp) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "animateCallConnected, current status: " + mCallStatus);
- }
- if (mCallStatus == CallStatus.INCOMING_OR_DIALING) {
- mCallStatus = CallStatus.ACTIVE;
-
- // Decrease priority after call is answered.
- runDelayed(3000, new Runnable() {
- @Override
- public void run() {
- setPriority(PRIORITY_CALL_ACTIVE);
- }
- });
-
- final long duration = 500 * DebugUtil.ANIMATION_FACTOR;
-
- TimeInterpolator interpolator =
- new AccelerateDecelerateInterpolator(getContext(), null);
-
- mCallDuration.setBase(connectedTimestamp);
- mCallDuration.start();
-
- mBackgroundImage.animate()
- .alpha(0f)
- .setDuration(duration);
-
- mLeftIconSwitcher.setTranslationX(mLeftPadding);
- mLeftIconSwitcher.setVisibility(VISIBLE);
- mRightIconSwitcher.animate()
- .translationX(mLeftPadding + mIconsOverlap)
- .setInterpolator(interpolator)
- .setDuration(duration);
- setRightIcon(
- BitmapFactory.decodeResource(getResources(), R.drawable.phone_active), true);
- mDetailsPanel.animate()
- .translationX(
- mLeftPadding + mIconsOverlap + mIconSize + mLeftPadding)
- .setInterpolator(interpolator)
- .setDuration(duration);
-
- mCallStatusTextView.animate()
- .alpha(0f)
- .setDuration(duration);
-
- mCallDurationPanel.setAlpha(0);
- mCallDurationPanel.setVisibility(VISIBLE);
- mCallDurationPanel.animate()
- .setDuration(duration)
- .alpha(1);
-
- mPhonePanel.animate()
- .translationYBy(-(mIncomingCallTextHeight + mCallDurationTextHeight) / 2)
- .setDuration(duration);
- }
- }
-
- public void animateCallDisconnected() {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "animateCallConnected, current status: " + mCallStatus);
- }
- if (mCallStatus == CallStatus.ACTIVE) {
- mCallStatus = CallStatus.DISCONNECTED;
-
- runDelayed(2000, new Runnable() {
- @Override
- public void run() {
- setPriority(PRIORITY_GARBAGE);
- }
- });
-
- mCallDuration.stop();
- final int duration = 500;
-
- TimeInterpolator interpolator =
- new AccelerateDecelerateInterpolator(getContext(), null);
-
- setRightIcon(
- BitmapFactory.decodeResource(getResources(), R.drawable.phone), true);
- mRightIconSwitcher.animate()
- .translationX(mLeftPadding)
- .setInterpolator(interpolator)
- .setDuration(duration * DebugUtil.ANIMATION_FACTOR)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- mLeftIconSwitcher.setVisibility(GONE);
- }
- });
- mDetailsPanel.animate()
- .translationX(mLeftPadding + mIconSize + mLeftPadding)
- .setInterpolator(interpolator)
- .setDuration(duration * DebugUtil.ANIMATION_FACTOR);
- }
- }
-
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/CardView.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/CardView.java
deleted file mode 100644
index 06c9fcc..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/CardView.java
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample.cards;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffXfermode;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.ViewGroup;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import android.widget.ViewSwitcher;
-
-import com.android.car.cluster.sample.DebugUtil;
-import com.android.car.cluster.sample.R;
-
-/**
- * View that responsible for displaying cards in instrument cluster (including media, phone and
- * maps).
- */
-public class CardView extends FrameLayout implements Comparable<CardView> {
-
- private final static String TAG = DebugUtil.getTag(CardView.class);
-
- protected final static long SHOW_ANIMATION_DURATION = 1000 * DebugUtil.ANIMATION_FACTOR;
-
- protected ImageView mBackgroundImage;
- protected ViewGroup mDetailsPanel;
- protected ViewSwitcher mLeftIconSwitcher;
- protected ViewSwitcher mRightIconSwitcher;
-
- private Bitmap mBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-
- protected long mLastUpdated = SystemClock.elapsedRealtime();
-
- private Canvas mCanvas = new Canvas();
- private final Paint mBackgroundCirclePaint;
-
- private final static Handler mHandler = new Handler(Looper.getMainLooper());
-
- protected final int mCardWidth;
- protected final int mCardHeight;
- protected final int mCurveRadius;
- protected final int mTextPanelWidth;
- protected final float mLeftPadding;
- protected final float mIconSize;
- protected final float mIconsOverlap;
-
- protected int mPriority = 9;
-
- protected final static int PRIORITY_GARBAGE = 10;
-
- protected final static int PRIORITY_CALL_INCOMING = 3;
- protected final static int PRIORITY_CALL_ACTIVE = 5;
- protected final static int PRIORITY_MEDIA_NOTIFICATION = 3;
- protected final static int PRIORITY_MEDIA_ACTIVE = 6;
- protected final static int PRIORITY_WEATHER_CARD = 9;
- protected final static int PRIORITY_NAVIGATION_ACTIVE = 3;
- protected final static int PRIORITY_HANGOUT_NOTIFICATION = 3;
-
- @CardType
- private int mCardType;
- private final PriorityChangedListener mPriorityChangedListener;
-
- public @interface CardType {
- int WEATHER = 1;
- int MEDIA = 2;
- int PHONE_CALL = 3;
- int NAV = 4;
- int HANGOUT = 5;
- }
-
- public CardView(Context context, @CardType int cardType, PriorityChangedListener listener) {
- this(context, null, cardType, listener);
- }
-
- public CardView(Context context, AttributeSet attrs, @CardType int cardType,
- PriorityChangedListener listener) {
- super(context, attrs);
- mPriorityChangedListener = listener;
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "ctor");
- }
- mCardType = cardType;
-
- setWillNotDraw(false); // This will trigger onDraw method.
-
- mBackgroundCirclePaint = createBackgroundCirclePaint();
- mCardWidth = (int)getResources().getDimension(R.dimen.card_width);
- mCardHeight = (int) getResources().getDimension(R.dimen.card_height);
- mTextPanelWidth = (int)getResources().getDimension(R.dimen.card_message_panel_width);
- mLeftPadding = getResources().getDimension(R.dimen.card_content_left_padding);
- mIconSize = getResources().getDimension(R.dimen.card_icon_size);
- mIconsOverlap = mIconSize - mLeftPadding;
- mCurveRadius = (int)(mCardWidth * 0.643f);
-
- inflate(getContext(), R.layout.card_view, this);
-
- if (this.isInEditMode()) {
- return;
- }
-
- mLeftIconSwitcher = viewById(R.id.left_icon_switcher);
- mRightIconSwitcher = viewById(R.id.right_icon_switcher);
- mBackgroundImage = viewById(R.id.image_background);
-
- init();
- }
-
- protected void inflate(int layoutId) {
- inflate(getContext(), layoutId, (ViewGroup) getChildAt(0));
- }
-
- protected void init() {
- }
-
- @CardType
- public int getCardType() {
- return mCardType;
- }
-
- public void setLeftIcon(Bitmap bitmap) {
- setLeftIcon(bitmap, false /* animated */);
- }
-
- public void setLeftIcon(Bitmap bitmap, boolean animated) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "setLeftIcon, bitmap: " + bitmap);
- }
- switchImageViewBitmpa(bitmap, mLeftIconSwitcher, animated);
- }
-
-
- public void setRightIcon(Bitmap bitmap) {
- setRightIcon(bitmap, false /* animated */);
- }
-
- /**
- * @param bitmap if null, the image won't be displayed and message panel will be placed
- * accordingly.
- */
- public void setRightIcon(Bitmap bitmap, boolean animated) {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "setRightIcon, bitmap: " + bitmap);
- }
- if (bitmap == null && mRightIconSwitcher.getVisibility() == VISIBLE) {
- mRightIconSwitcher.setVisibility(GONE);
- } else if (bitmap != null && mRightIconSwitcher.getVisibility() == GONE) {
- mRightIconSwitcher.setVisibility(VISIBLE);
- }
-
- switchImageViewBitmpa(bitmap, mRightIconSwitcher, animated);
- }
-
- private void switchImageViewBitmpa(Bitmap bitmap, ViewSwitcher switcher, boolean animated) {
- ImageView icon = (ImageView) (animated
- ? switcher.getNextView() : switcher.getCurrentView());
-
- icon.setBackground(null);
- icon.setImageBitmap(bitmap);
-
- if (animated) {
- switcher.showNext();
- }
- }
-
- /** Called by {@code ClusterView} when card should go away using unreveal animation */
- public void onPlayUnrevealAnimation() {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "onPlayUnrevealAnimation");
- }
- }
-
- public void onPlayRevealAnimation() {
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "onPlayRevealAnimation");
- }
-
- if (mLeftIconSwitcher.getVisibility() == VISIBLE) {
- mLeftIconSwitcher.setTranslationX(mCardWidth / 2);
- mLeftIconSwitcher.animate()
- .translationX(getLeftIconTargetX())
- .setDuration(SHOW_ANIMATION_DURATION)
- .setInterpolator(getDecelerateInterpolator());
- }
-
- if (mRightIconSwitcher.getVisibility() == VISIBLE) {
- mRightIconSwitcher.setTranslationX( mCardWidth - mTextPanelWidth / 2 - mIconSize);
- mRightIconSwitcher.animate()
- .translationX(getRightIconTargetX())
- .setDuration(SHOW_ANIMATION_DURATION)
- .setInterpolator(getDecelerateInterpolator());
- }
-
- showDetailsPanelAnimation(getDetailsPanelTargetX());
- }
-
- protected float getLeftIconTargetX() {
- return mLeftIconSwitcher.getVisibility() == VISIBLE ? mLeftPadding : 0;
- }
-
- protected float getRightIconTargetX() {
- if (mRightIconSwitcher.getVisibility() != VISIBLE) {
- return 0;
- }
- float x = mLeftPadding;
- if (mLeftIconSwitcher.getVisibility() == VISIBLE) {
- x += mIconsOverlap;
- }
- return x;
- }
-
- protected float getDetailsPanelTargetX() {
- return Math.max(getLeftIconTargetX(), getRightIconTargetX()) + mIconSize + mLeftPadding;
- }
-
- protected void showDetailsPanelAnimation(float textX) {
- if (mDetailsPanel != null) {
- mDetailsPanel.setTranslationX(mCardWidth - mTextPanelWidth / 2);
- mDetailsPanel.animate()
- .translationX(textX)
- .setDuration(SHOW_ANIMATION_DURATION)
- .setInterpolator(getDecelerateInterpolator());
- }
- }
-
- protected DecelerateInterpolator getDecelerateInterpolator() {
- return new DecelerateInterpolator(2f);
- }
-
- public void setBackground(Bitmap bmpPicture, int backgroundColor) {
- Bitmap bmpBackground = Bitmap.createBitmap(
- mCardWidth,
- (int)getResources().getDimension(R.dimen.card_height),
- Config.ARGB_8888);
- Canvas canvas = new Canvas(bmpBackground);
- //clear previous drawings
- canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
-
- Paint p = new Paint();
- p.setColor(backgroundColor);
- p.setAntiAlias(true);
- p.setStyle(Style.FILL);
- // Draw curved background.
- canvas.drawCircle(mCurveRadius, (int)getResources().getDimension(
- R.dimen.card_height) / 2,
- mCurveRadius, p);
-
- // Draw image respecting curved background.
- p.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
- float x = canvas.getWidth() - bmpPicture.getWidth();
- float y = canvas.getHeight() - bmpPicture.getHeight();
- if (y < 0) {
- y = y / 2; // Center image if it is not fitting.
- }
- canvas.drawBitmap(bmpPicture, x, y, p);
-
- mBackgroundImage.setScaleType(ScaleType.CENTER_CROP);
- mBackgroundImage.setImageBitmap(bmpBackground);
- if (mBackgroundImage.getVisibility() != VISIBLE) {
- mBackgroundImage.setVisibility(VISIBLE);
- }
- }
-
- public void setBackgroundColor(int color) {
- mBackgroundCirclePaint.setColor(color);
- }
-
- private Paint createBackgroundCirclePaint() {
- Paint p = new Paint();
- p.setAntiAlias(true);
- p.setXfermode(new PorterDuffXfermode(Mode.ADD));
- p.setStyle(Style.FILL);
- p.setColor(getResources().getColor(R.color.cluster_active_area_background, null));
- return p;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if(mBitmap.isRecycled() || mBitmap.getWidth() != canvas.getWidth()
- || mBitmap.getHeight() != canvas.getHeight()) {
- Log.d(TAG, "creating bitmap...");
- mBitmap.recycle();
- mBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888);
- mCanvas.setBitmap(mBitmap);
- }
-
- //clear previous drawings
- mCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
-
- mCanvas.drawCircle(mCurveRadius, getHeight() / 2, mCurveRadius, mBackgroundCirclePaint);
-
- canvas.drawBitmap(mBitmap, 0, 0, null);
- }
-
- public int getIconSize() {
- return (int)mIconSize;
- }
-
- public static void runDelayed(long delay, final Runnable task) {
- mHandler.postDelayed(task, delay);
- }
-
- public void setPriority(int priority) {
- mPriority = priority;
- mPriorityChangedListener.onPriorityChanged(this, priority);
- }
-
- /**
- * Should return number from 0 to 9. 0 - is most important, 9 is less important.
- */
- public int getPriority() {
- return mPriority;
- }
-
- public boolean isGarbage() {
- return getPriority() == PRIORITY_GARBAGE;
- }
-
- public void removeGracefully() {
- setPriority(PRIORITY_GARBAGE);
- }
-
- @Override
- public int compareTo(CardView another) {
- int res = this.getPriority() - another.getPriority();
- if (res == 0) {
- // If objects have the same priorities, check the last time they were updated.
- res = this.mLastUpdated > another.mLastUpdated ? -1 : 1;
- if (DebugUtil.DEBUG) {
- Log.d(TAG, "Found card with the same priority: " + this + " and " + another + ","
- + "this.mLastUpdated: " + mLastUpdated
- + ", another.mLastUpdated:" + another.mLastUpdated + ", res: " + res);
-
- }
- }
- return res;
- }
-
- @SuppressWarnings("unchecked")
- protected <E> E viewById(int id) {
- return (E) findViewById(id);
- }
-
- public interface PriorityChangedListener {
- void onPriorityChanged(CardView cardView, int newPriority);
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/MediaCard.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/MediaCard.java
deleted file mode 100644
index a20dffe..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/MediaCard.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample.cards;
-
-import android.animation.TimeInterpolator;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import com.android.car.cluster.sample.DebugUtil;
-import com.android.car.cluster.sample.R;
-
-/**
- * Card responsible to display media content.
- */
-public class MediaCard extends CardView {
-
- private LinearLayout mMediaPanel;
- private ProgressBar mProgressBar;
- private TextView mTitle;
- private TextView mSubtitle;
-
- public MediaCard(Context context, PriorityChangedListener listener) {
- super(context, CardType.MEDIA, listener);
- }
-
- @Override
- protected void init() {
- inflate(R.layout.media_card);
-
- mPriority = PRIORITY_MEDIA_NOTIFICATION;
-
- mMediaPanel = viewById(R.id.message_panel);
- mProgressBar = viewById(R.id.progress_bar);
- mTitle = viewById(R.id.media_title);
- mSubtitle = viewById(R.id.media_subtitle);
-
- mDetailsPanel = mMediaPanel;
- mLeftIconSwitcher.setVisibility(GONE);
- }
-
- @Override
- public void onPlayRevealAnimation() {
- super.onPlayRevealAnimation();
-
- // Decrease priority once notification animation is complete.
- runDelayed(3000, new Runnable() {
- @Override
- public void run() {
- setPriority(PRIORITY_MEDIA_ACTIVE);
- }
- });
-
- if (mBackgroundImage.getVisibility() != GONE) {
- runDelayed(SHOW_ANIMATION_DURATION + 3000, new Runnable() {
- @Override
- public void run() {
- animateBackgroundFadeOut();
- }
- });
- }
- }
-
- private void animateBackgroundFadeOut() {
- TimeInterpolator interpolator =
- new AccelerateDecelerateInterpolator(getContext(), null);
-
- long duration = 500 * DebugUtil.ANIMATION_FACTOR;
-
- mBackgroundImage.animate()
- .alpha(0f)
- .setDuration(duration);
-
- mLeftIconSwitcher.setTranslationX(mLeftPadding);
- mLeftIconSwitcher.setVisibility(VISIBLE);
- mRightIconSwitcher.animate()
- .translationX(mLeftPadding + mIconsOverlap)
- .setInterpolator(interpolator)
- .setDuration(duration);
-
- mDetailsPanel.animate()
- .translationX(
- mLeftPadding + mIconsOverlap + mIconSize + mLeftPadding)
- .setInterpolator(interpolator)
- .setDuration(duration);
-
- }
-
- public void setProgressColor(int color) {
- mProgressBar.getIndeterminateDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN);
- mProgressBar.setProgressTintList(ColorStateList.valueOf(color));
- }
-
- public void setProgress(int progress) {
- if (progress == -1) {
- mProgressBar.setIndeterminate(true);
- return;
- } else {
- mProgressBar.setIndeterminate(false);
- }
-
- if (progress > 100) {
- progress = 100;
- }
- if (progress < 0) {
- progress = 0;
- }
- mProgressBar.setProgress(progress);
- }
-
- public void setTitle(String album) {
- mTitle.setText(album);
- }
-
- public void setSubtitle(String track) {
- mSubtitle.setText(track);
- }
-
- public String getTitle() {
- return mTitle.getText() == null ? null : String.valueOf(mTitle.getText());
- }
-
- public String getSubtitle() {
- return mSubtitle.getText() == null ? null : String.valueOf(mSubtitle.getText());
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/MessageCard.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/MessageCard.java
deleted file mode 100644
index 7a878da..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/MessageCard.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample.cards;
-
-import android.content.Context;
-import android.graphics.BitmapFactory;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import com.android.car.cluster.sample.R;
-
-/**
- * Card that represents hangout notification.
- */
-public class MessageCard extends CardView {
-
- private TextView mContactName;
-
- public MessageCard(Context context, PriorityChangedListener listener) {
- this(context, null, CardType.HANGOUT, listener);
- }
-
- public MessageCard(Context context, AttributeSet attrs, @CardType int cardType,
- PriorityChangedListener listener) {
- super(context, attrs, cardType, listener);
- }
-
- @Override
- protected void init() {
- super.init();
-
- inflate(R.layout.hangout_layout);
-
- mDetailsPanel = viewById(R.id.msg_text_panel);
- mContactName = viewById(R.id.msg_card_contact_name);
- setRightIcon(BitmapFactory.decodeResource(getResources(), R.drawable.hangouts_icon));
-
- mPriority = PRIORITY_HANGOUT_NOTIFICATION;
-
- // Remove this notification in 5 seconds.
- runDelayed(5000, new Runnable() {
- @Override
- public void run() {
- removeGracefully();
- }
- });
- }
-
- public void setContactName(String contactName) {
- mContactName.setText(contactName);
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/NavCard.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/NavCard.java
deleted file mode 100644
index 0253184..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/NavCard.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample.cards;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ViewSwitcher;
-import android.widget.ViewSwitcher.ViewFactory;
-
-import com.android.car.cluster.sample.ManeuverPanel;
-import com.android.car.cluster.sample.R;
-
-/**
- * Card responsible for showing navigation.
- */
-public class NavCard extends CardView {
-
- private ViewSwitcher mDirectionsSwitcher;
-
- public NavCard(Context context, PriorityChangedListener listener) {
- this(context, null, CardType.NAV, listener);
- }
-
- public NavCard(Context context, AttributeSet attrs, @CardType int cardType,
- PriorityChangedListener listener) {
- super(context, attrs, cardType, listener);
-
- }
-
- @Override
- protected void init() {
- inflate(R.layout.nav_card);
-
- mPriority = PRIORITY_NAVIGATION_ACTIVE;
-
- mDirectionsSwitcher = viewById(R.id.nav_directions_switcher);
- mDetailsPanel = mDirectionsSwitcher;
-
- mDirectionsSwitcher.setFactory(new ViewFactory() {
- @Override
- public View makeView() {
- return new ManeuverPanel(getContext());
- }
- });
-
- setRightIcon(null); // To hide it.
- }
-
- public void setDistanceToNextManeuver(String distance, String units) {
- ManeuverPanel maneuver = (ManeuverPanel) mDirectionsSwitcher.getCurrentView();
- maneuver.setDistanceToNextManeuver(distance, units);
- }
-
- public void setStreet(CharSequence street) {
- ManeuverPanel maneuver = (ManeuverPanel) mDirectionsSwitcher.getNextView();
- maneuver.setStreet(street);
- mDirectionsSwitcher.showNext();
- }
-
- public void setManeuverImage(Bitmap maneuverImage) {
- setLeftIcon(maneuverImage, true /* animated */);
- }
-
- @Override
- public void onPlayRevealAnimation() {
- super.onPlayRevealAnimation();
- }
-}
diff --git a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/WeatherCard.java b/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/WeatherCard.java
deleted file mode 100644
index 8ab6b24..0000000
--- a/tests/InstrumentClusterRendererSample/src/com/android/car/cluster/sample/cards/WeatherCard.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cluster.sample.cards;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.ImageView;
-
-import com.android.car.cluster.sample.DebugUtil;
-import com.android.car.cluster.sample.R;
-
-/**
- * Sample card responsible for displaying weather content.
- */
-public class WeatherCard extends CardView {
-
- private ImageView mFarCloudImage;
- private ImageView mNearCloudImage;
-
- public WeatherCard(Context context, PriorityChangedListener listener) {
- super(context, CardType.WEATHER, listener);
- }
-
- @Override
- protected void init() {
- inflate(R.layout.weather_card);
-
- mPriority = PRIORITY_WEATHER_CARD;
- mFarCloudImage = viewById(R.id.weather_far_cloud);
- mNearCloudImage = viewById(R.id.weather_near_cloud);
-
- mDetailsPanel = viewById(R.id.weather_panel);;
- Bitmap theSun = BitmapFactory.decodeResource(getResources(), R.drawable.sun_154);
- setLeftIcon(theSun);
- mLeftIconSwitcher.setVisibility(VISIBLE);
- ((ImageView)mRightIconSwitcher.getCurrentView()).setImageDrawable(
- getResources().getDrawable(R.drawable.cloud_154_shadow, null));
- mRightIconSwitcher.setVisibility(VISIBLE);
- }
-
- @Override
- public void onPlayRevealAnimation() {
- super.onPlayRevealAnimation();
- long duration = SHOW_ANIMATION_DURATION * DebugUtil.ANIMATION_FACTOR;
-
- mNearCloudImage.setTranslationX(400);
- mNearCloudImage.animate()
- .translationX(0)
- .setDuration(duration)
- .setInterpolator(new DecelerateInterpolator(2f));
-
- // Far cloud needs to travel less in screen coordinates so it will make it slower.
- mFarCloudImage.setTranslationX(100);
- mFarCloudImage.animate()
- .translationX(0)
- .setDuration(duration)
- .setInterpolator(new DecelerateInterpolator(2f));
- }
-
- @Override
- protected float getRightIconTargetX() {
- return super.getRightIconTargetX() - 22;
- }
-
- @Override
- protected float getDetailsPanelTargetX() {
- return super.getDetailsPanelTargetX() - 70;
- }
-}
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-as/strings.xml
similarity index 62%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-as/strings.xml
index daa61a3..f4490dc 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-as/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"নমস্কাৰ, পৃথিৱী!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-bn/strings.xml
similarity index 62%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-bn/strings.xml
index daa61a3..a27bebe 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-bn/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"হ্যালো, ওয়ার্ল্ড!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-eu/strings.xml
similarity index 64%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-eu/strings.xml
index daa61a3..ff1a717 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-eu/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"Kaixo!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-gu/strings.xml
similarity index 62%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-gu/strings.xml
index daa61a3..ad17840 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-gu/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"વિશ્વને નમસ્કાર!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-hi/strings.xml
similarity index 62%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-hi/strings.xml
index daa61a3..5e6e732 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-hi/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"सभी को नमस्कार!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-iw/strings.xml
similarity index 64%
rename from car-cluster-logging-renderer/res/values-af/strings.xml
rename to tests/MultiDisplayTestHelloActivity/res/values-iw/strings.xml
index daa61a3..d5c90ec 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-iw/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"Hello world!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-ka/strings.xml
similarity index 62%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-ka/strings.xml
index daa61a3..fb1ff2f 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-ka/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"გამარჯობა, სამყაროვ!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-kk/strings.xml
similarity index 63%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-kk/strings.xml
index daa61a3..71dc98e 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-kk/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"Бәріне сәлем!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-kn/strings.xml
similarity index 62%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-kn/strings.xml
index daa61a3..283e7ac 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-kn/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"ಈ ಜಗತ್ತಿಗೆ, ನಮಸ್ಕಾರ!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-ml/strings.xml
similarity index 63%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-ml/strings.xml
index daa61a3..353fd0d 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-ml/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"ഹലോ, വേൾഡ്!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-mr/strings.xml
similarity index 63%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-mr/strings.xml
index daa61a3..b143ba3 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-mr/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"हॅलो, दुनिया!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-ne/strings.xml
similarity index 62%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-ne/strings.xml
index daa61a3..6ab57f4 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-ne/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"संसारलाई नमस्कार!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-or/strings.xml
similarity index 63%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-or/strings.xml
index daa61a3..9a18aae 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-or/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"ହେଲୋ ଦୁନିଆ!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-ta/strings.xml
similarity index 61%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-ta/strings.xml
index daa61a3..6faf2cd 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-ta/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"உலகத்தினருக்கு வணக்கம்!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-te/strings.xml
similarity index 63%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-te/strings.xml
index daa61a3..0ed1751 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-te/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"హలో ప్రపంచం!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-ur/strings.xml
similarity index 63%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-ur/strings.xml
index daa61a3..ffb21af 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-ur/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"ہیلو، دنیا والو!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-uz/strings.xml
similarity index 64%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-uz/strings.xml
index daa61a3..f44363a 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-uz/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"Salom, dunyo!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/car-cluster-logging-renderer/res/values-af/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-zh-rCN/strings.xml
similarity index 64%
copy from car-cluster-logging-renderer/res/values-af/strings.xml
copy to tests/MultiDisplayTestHelloActivity/res/values-zh-rCN/strings.xml
index daa61a3..da391de 100644
--- a/car-cluster-logging-renderer/res/values-af/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-zh-rCN/strings.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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
+ 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,
@@ -16,5 +16,7 @@
<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>
+ <string name="hello_activity_text_text" msgid="8189259382863353832">"Hello, World!"</string>
+ <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
+ <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
</resources>
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
index 2fc57eb..7a3b7b5 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
@@ -120,13 +120,13 @@
for (int areaId : areaIds) {
assertTrue(property.hasArea(areaId));
- int min = property.getMinValue(areaId);
- int max = property.getMaxValue(areaId);
+ int min = property.getMinValue(areaId) == null ? 0 : property.getMinValue(areaId);
+ int max = property.getMaxValue(areaId) == null ? 0 : property.getMaxValue(areaId);
assertTrue(min <= max);
}
} else {
- int min = property.getMinValue();
- int max = property.getMaxValue();
+ int min = property.getMinValue() == null ? 0 : property.getMinValue();
+ int max = property.getMaxValue() == null ? 0 : property.getMinValue();
assertTrue(min <= max);
for (int i = 0; i < 32; i++) {
assertFalse(property.hasArea(0x1 << i));
@@ -143,15 +143,17 @@
assertTrue(areaIds.length > 0);
assertEquals(areaIds.length, property.getAreaCount());
- for (int areId : areaIds) {
- assertTrue(property.hasArea(areId));
- float min = property.getMinValue(areId);
- float max = property.getMaxValue(areId);
+ for (int areaId : areaIds) {
+ assertTrue(property.hasArea(areaId));
+ float min =
+ property.getMinValue(areaId) == null ? 0f : property.getMinValue(areaId);
+ float max =
+ property.getMaxValue(areaId) == null ? 0f : property.getMinValue(areaId);
assertTrue(min <= max);
}
} else {
- float min = property.getMinValue();
- float max = property.getMaxValue();
+ float min = property.getMinValue() == null ? 0f : property.getMinValue();
+ float max = property.getMaxValue() == null ? 0f : property.getMinValue();
assertTrue(min <= max);
for (int i = 0; i < 32; i++) {
assertFalse(property.hasArea(0x1 << i));
diff --git a/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java b/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
index ee08226..aadb6f9 100644
--- a/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
@@ -28,12 +28,14 @@
import static org.mockito.Mockito.when;
import android.car.drivingstate.CarDrivingStateEvent;
+import android.car.drivingstate.CarUxRestrictions;
import android.car.drivingstate.CarUxRestrictionsConfiguration;
import android.car.drivingstate.CarUxRestrictionsConfiguration.Builder;
import android.car.hardware.CarPropertyValue;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.os.SystemClock;
import android.util.JsonReader;
import android.util.JsonWriter;
@@ -206,6 +208,18 @@
createEmptyConfig((byte) 0), createEmptyConfig((byte) 0)));
}
+ @Test
+ public void testGetCurrentUxRestrictions_UnknownDisplayId_ReturnsFullRestrictions()
+ throws Exception {
+ mService.init();
+ CarUxRestrictions restrictions = mService.getCurrentUxRestrictions(/* displayId= */ 10);
+ CarUxRestrictions expected = new CarUxRestrictions.Builder(
+ /*reqOpt= */ true,
+ CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED,
+ SystemClock.elapsedRealtimeNanos()).build();
+ assertTrue(restrictions.toString(), expected.isSameRestrictions(restrictions));
+ }
+
private CarUxRestrictionsConfiguration createEmptyConfig() {
return createEmptyConfig(null);
}
diff --git a/tests/carservice_test/src/com/android/car/MockedVmsTestBase.java b/tests/carservice_test/src/com/android/car/MockedVmsTestBase.java
index 4c26e11..7214f8b 100644
--- a/tests/carservice_test/src/com/android/car/MockedVmsTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedVmsTestBase.java
@@ -16,6 +16,7 @@
package com.android.car;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.car.Car;
import android.car.VehicleAreaType;
@@ -30,7 +31,9 @@
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
import android.hardware.automotive.vehicle.V2_0.VmsAvailabilityStateIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_0.VmsBaseMessageIntegerValuesIndex;
import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
+import android.hardware.automotive.vehicle.V2_0.VmsStartSessionMessageIntegerValuesIndex;
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
@@ -38,6 +41,8 @@
import com.android.car.vehiclehal.VehiclePropValueBuilder;
import com.android.car.vehiclehal.test.MockedVehicleHal;
+import org.junit.Before;
+
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
@@ -73,10 +78,8 @@
.addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 0, 0);
}
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
+ @Before
+ public void setUpVms() throws Exception {
// Trigger VmsClientManager to bind to the MockPublisherClient
getContext().sendBroadcastAsUser(new Intent(Intent.ACTION_USER_UNLOCKED), UserHandle.ALL);
@@ -86,8 +89,23 @@
mVmsSubscriberManager.setVmsSubscriberClientCallback(Executors.newSingleThreadExecutor(),
mSubscriberClient);
- // Validate layer availability sent to HAL
+ // Validate session handshake
List<Integer> v = mHalClient.receiveMessage().value.int32Values;
+ assertEquals(VmsMessageType.START_SESSION,
+ (int) v.get(VmsBaseMessageIntegerValuesIndex.MESSAGE_TYPE));
+ int coreId = v.get(VmsStartSessionMessageIntegerValuesIndex.SERVICE_ID);
+ assertTrue(coreId > 0);
+ assertEquals(-1, (int) v.get(VmsStartSessionMessageIntegerValuesIndex.CLIENT_ID));
+
+ // Send handshake acknowledgement
+ mHalClient.sendMessage(
+ VmsMessageType.START_SESSION,
+ coreId,
+ 12345 // Client ID
+ );
+
+ // Validate layer availability sent to HAL
+ v = mHalClient.receiveMessage().value.int32Values;
assertEquals(VmsMessageType.AVAILABILITY_CHANGE,
(int) v.get(VmsAvailabilityStateIntegerValuesIndex.MESSAGE_TYPE));
assertEquals(0,
@@ -107,16 +125,12 @@
return mVmsSubscriberManager;
}
- Pair<VmsLayer, byte[]> receiveDataMessage() throws InterruptedException {
- return receiveWithTimeout(mSubscriberClient.mMessages);
- }
-
- VmsAvailableLayers receiveLayerAvailability() throws InterruptedException {
- return receiveWithTimeout(mSubscriberClient.mAvailableLayers);
- }
-
- MockPublisherClient getMockPublisherClient() throws InterruptedException {
- sPublisherIsReady.await(2L, TimeUnit.SECONDS);
+ MockPublisherClient getMockPublisherClient() {
+ try {
+ sPublisherIsReady.await(2L, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
return sPublisherClient;
}
@@ -145,7 +159,7 @@
mSubscriptionState.add(subscriptionState);
}
- VmsSubscriptionState receiveSubscriptionState() throws InterruptedException {
+ VmsSubscriptionState receiveSubscriptionState() {
return receiveWithTimeout(mSubscriptionState);
}
}
@@ -166,11 +180,11 @@
mAvailableLayers.add(availableLayers);
}
- Pair<VmsLayer, byte[]> receiveMessage() throws InterruptedException {
+ Pair<VmsLayer, byte[]> receiveMessage() {
return receiveWithTimeout(mMessages);
}
- VmsAvailableLayers receiveLayerAvailability() throws InterruptedException {
+ VmsAvailableLayers receiveLayerAvailability() {
return receiveWithTimeout(mAvailableLayers);
}
}
@@ -201,12 +215,16 @@
.build());
}
- VehiclePropValue receiveMessage() throws InterruptedException {
+ VehiclePropValue receiveMessage() {
return receiveWithTimeout(mMessages);
}
}
- private static <T> T receiveWithTimeout(BlockingQueue<T> queue) throws InterruptedException {
- return queue.poll(2L, TimeUnit.SECONDS);
+ private static <T> T receiveWithTimeout(BlockingQueue<T> queue) {
+ try {
+ return queue.poll(2L, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java b/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java
index 82b89ec..87cf1b8 100644
--- a/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java
@@ -18,107 +18,582 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
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.car.vms.VmsSubscriberManager;
+import android.car.vms.VmsSubscriptionState;
import android.util.Pair;
import androidx.test.filters.MediumTest;
+import org.junit.Before;
import org.junit.Test;
-import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
+import java.util.function.Supplier;
+import java.util.function.ToIntFunction;
@MediumTest
public class VmsPublisherSubscriberTest extends MockedVmsTestBase {
- private static final int LAYER_ID = 88;
- private static final int LAYER_VERSION = 19;
- private static final int LAYER_SUBTYPE = 55;
- private static final String TAG = "VmsPubSubTest";
+ private static final VmsLayer SUBSCRIPTION_LAYER = new VmsLayer(1, 1, 1);
+ private static final VmsLayer SUBSCRIPTION_LAYER_OTHER = new VmsLayer(2, 1, 1);
- // The expected publisher ID is 0 since it the expected assigned ID from the VMS core.
- public static final int EXPECTED_PUBLISHER_ID = 0;
- public static final VmsLayer LAYER = new VmsLayer(LAYER_ID, LAYER_SUBTYPE, LAYER_VERSION);
- public static final VmsAssociatedLayer ASSOCIATED_LAYER =
- new VmsAssociatedLayer(LAYER, new HashSet<>(Arrays.asList(EXPECTED_PUBLISHER_ID)));
- public static final byte[] PAYLOAD = new byte[]{2, 3, 5, 7, 11, 13, 17};
+ private static final byte[] PAYLOAD = {0xa, 0xb};
+ private static final byte[] PAYLOAD_OTHER = {0xb, 0xc};
- private static final List<VmsAssociatedLayer> AVAILABLE_ASSOCIATED_LAYERS =
- new ArrayList<>(Arrays.asList(ASSOCIATED_LAYER));
- private static final VmsAvailableLayers AVAILABLE_LAYERS_WITH_SEQ =
- new VmsAvailableLayers(
- new HashSet(AVAILABLE_ASSOCIATED_LAYERS), 1);
+ private static final byte[] PUBLISHER_INFO = {0x0};
+ private static final byte[] PUBLISHER_INFO_OTHER = {0x1};
+ private static final int UNKNOWN_PUBLISHER = 99999;
- private static final int SUBSCRIBED_LAYER_ID = 89;
- public static final VmsLayer SUBSCRIBED_LAYER =
- new VmsLayer(SUBSCRIBED_LAYER_ID, LAYER_SUBTYPE, LAYER_VERSION);
- public static final VmsAssociatedLayer ASSOCIATED_SUBSCRIBED_LAYER =
- new VmsAssociatedLayer(SUBSCRIBED_LAYER,
- new HashSet<>(Arrays.asList(EXPECTED_PUBLISHER_ID)));
- private static final List<VmsAssociatedLayer>
- AVAILABLE_ASSOCIATED_LAYERS_WITH_SUBSCRIBED_LAYER =
- new ArrayList<>(Arrays.asList(ASSOCIATED_LAYER, ASSOCIATED_SUBSCRIBED_LAYER));
- private static final VmsAvailableLayers AVAILABLE_LAYERS_WITH_SUBSCRIBED_LAYER_WITH_SEQ =
- new VmsAvailableLayers(
- new HashSet(AVAILABLE_ASSOCIATED_LAYERS_WITH_SUBSCRIBED_LAYER), 1);
+ private MockPublisherClient mPublisher;
+ private VmsSubscriberManager mSubscriber;
+ private MockSubscriberClient mSubscriberClient;
- /*
- * This test method subscribes to a layer and triggers
- * VmsPublisherClientMockService.onVmsSubscriptionChange. In turn, the mock service will publish
- * a message, which is validated in this test.
- */
- @Test
- public void testPublisherToSubscriber() throws Exception {
- getSubscriberManager().subscribe(LAYER);
-
- int publisherId = getMockPublisherClient().getPublisherId(PAYLOAD);
- getMockPublisherClient().publish(LAYER, publisherId, PAYLOAD);
-
- Pair<VmsLayer, byte[]> dataMessage = receiveDataMessage();
- assertEquals(LAYER, dataMessage.first);
- assertArrayEquals(PAYLOAD, dataMessage.second);
+ @Before
+ public void setUpClients() {
+ mPublisher = getMockPublisherClient();
+ mSubscriber = getSubscriberManager();
+ mSubscriberClient = getMockSubscriberClient();
}
- /**
- * The Mock service will get a publisher ID by sending its information when it will get
- * ServiceReady as well as on SubscriptionChange. Since clients are not notified when
- * publishers are assigned IDs, this test waits until the availability is changed which
- * indicates
- * that the Mock service has gotten its ServiceReady and publisherId.
- */
@Test
- public void testPublisherInfo() throws Exception {
- int publisherId = getMockPublisherClient().getPublisherId(PAYLOAD);
- byte[] info = getSubscriberManager().getPublisherInfo(publisherId);
- assertArrayEquals(PAYLOAD, info);
+ public void testPublisherInfo_Unregistered() {
+ assertEquals(0, mSubscriber.getPublisherInfo(UNKNOWN_PUBLISHER).length);
}
- /*
- * The Mock service offers all the subscribed layers as available layers.
- * In this test the client subscribes to a layer and verifies that it gets the
- * notification that it is available.
- */
@Test
- public void testAvailabilityWithSubscription() throws Exception {
- int publisherId = getMockPublisherClient().getPublisherId(PAYLOAD);
- getMockPublisherClient().setLayersOffering(new VmsLayersOffering(
- new HashSet<>(Arrays.asList(
- new VmsLayerDependency(LAYER),
- new VmsLayerDependency(SUBSCRIBED_LAYER))),
+ public void testPublisherInfo_Registered() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ assertArrayEquals(PUBLISHER_INFO, mSubscriber.getPublisherInfo(publisherId));
+ }
+
+ @Test
+ public void testPublisherId_AlreadyRegistered() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO);
+ assertEquals(publisherId, publisherId2);
+ }
+
+ @Test
+ public void testPublisherId_MultiplePublishers() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+ assertNotEquals(publisherId, publisherId2);
+ assertArrayEquals(PUBLISHER_INFO, mSubscriber.getPublisherInfo(publisherId));
+ assertArrayEquals(PUBLISHER_INFO_OTHER, mSubscriber.getPublisherInfo(publisherId2));
+ }
+
+ @Test
+ public void testLayerAvailability_Default() {
+ VmsAvailableLayers availableLayers = mSubscriber.getAvailableLayers();
+ assertEquals(Collections.emptySet(), availableLayers.getAssociatedLayers());
+ assertEquals(0, availableLayers.getSequence());
+ }
+
+ @Test
+ public void testLayerAvailability() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER, Collections.emptySet())), publisherId));
+
+ assertLayerAvailability(1,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId)));
+ }
+
+ @Test
+ public void testLayerAvailability_Overwrite() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER, Collections.emptySet())), publisherId));
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER_OTHER, Collections.emptySet())),
publisherId));
- Set<VmsAssociatedLayer> associatedLayers =
- AVAILABLE_LAYERS_WITH_SUBSCRIBED_LAYER_WITH_SEQ.getAssociatedLayers();
- assertEquals(associatedLayers, receiveLayerAvailability().getAssociatedLayers());
- assertEquals(associatedLayers,
- getSubscriberManager().getAvailableLayers().getAssociatedLayers());
+ assertLayerAvailability(2,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER_OTHER,
+ Collections.singleton(publisherId)));
+ }
+
+ @Test
+ public void testLayerAvailability_MultiplePublishers_SameLayer() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER, Collections.emptySet())), publisherId));
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER, Collections.emptySet())), publisherId2));
+
+ assertLayerAvailability(2,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER,
+ new HashSet<>(Arrays.asList(publisherId, publisherId2))));
+ }
+
+ @Test
+ public void testLayerAvailability_MultiplePublishers_MultipleLayers() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER, Collections.emptySet())), publisherId));
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER_OTHER, Collections.emptySet())),
+ publisherId2));
+
+ assertLayerAvailability(2,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId)),
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER_OTHER,
+ Collections.singleton(publisherId2)));
+ }
+
+ @Test
+ public void testLayerAvailability_MultiplePublishers_Remove() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER, Collections.emptySet())), publisherId));
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER, Collections.emptySet())), publisherId2));
+
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.emptySet(), publisherId2));
+
+ assertLayerAvailability(3,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId)));
+ }
+
+ @Test
+ public void testLayerAvailability_MultiplePublishers_Overwrite() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER, Collections.emptySet())), publisherId));
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER, Collections.emptySet())), publisherId2));
+
+ mPublisher.setLayersOffering(new VmsLayersOffering(Collections.singleton(
+ new VmsLayerDependency(SUBSCRIPTION_LAYER_OTHER, Collections.emptySet())),
+ publisherId2));
+
+ assertLayerAvailability(3,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId)),
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER_OTHER,
+ Collections.singleton(publisherId2)));
+ }
+
+ @Test
+ public void testStartMonitoring() {
+ mSubscriber.startMonitoring();
+ assertNull(mPublisher.receiveSubscriptionState());
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+ }
+
+ @Test
+ public void testStartMonitoring_AfterPublish() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+
+ mSubscriber.startMonitoring();
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testStartMonitoring_MultipleLayers() {
+ mSubscriber.startMonitoring();
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+
+ mPublisher.publish(SUBSCRIPTION_LAYER_OTHER, publisherId, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER_OTHER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testStartMonitoring_MultiplePublishers() {
+ mSubscriber.startMonitoring();
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId2, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testStopMonitoring() {
+ mSubscriber.startMonitoring();
+ mSubscriber.stopMonitoring();
+ assertNull(mPublisher.receiveSubscriptionState());
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testSubscribe() {
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+ assertSubscriptionState(1, SUBSCRIPTION_LAYER);
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+ }
+
+ @Test
+ public void testSubscribe_AfterPublish() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+
+ assertSubscriptionState(1, SUBSCRIPTION_LAYER);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testSubscribe_MultipleLayers() {
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER_OTHER);
+ assertSubscriptionState(2, SUBSCRIPTION_LAYER, SUBSCRIPTION_LAYER_OTHER);
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+
+ mPublisher.publish(SUBSCRIPTION_LAYER_OTHER, publisherId, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER_OTHER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testSubscribe_MultiplePublishers() {
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+ assertSubscriptionState(1, SUBSCRIPTION_LAYER);
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId2, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testSubscribe_MultipleLayers_MultiplePublishers() {
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER_OTHER);
+ assertSubscriptionState(2, SUBSCRIPTION_LAYER, SUBSCRIPTION_LAYER_OTHER);
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+ mPublisher.publish(SUBSCRIPTION_LAYER_OTHER, publisherId2, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER_OTHER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testSubscribe_ClearCallback() {
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+ mSubscriber.clearVmsSubscriberClientCallback();
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testSubscribe_NoCallback() {
+ mSubscriber.clearVmsSubscriberClientCallback();
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+ }
+
+ @Test
+ public void testUnsubscribe() {
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+ mSubscriber.unsubscribe(SUBSCRIPTION_LAYER);
+ assertSubscriptionState(2, Collections.emptySet(), Collections.emptySet());
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testUnsubscribe_MultipleLayers() {
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER_OTHER);
+ mSubscriber.unsubscribe(SUBSCRIPTION_LAYER);
+ assertSubscriptionState(3, SUBSCRIPTION_LAYER_OTHER);
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+
+ mPublisher.publish(SUBSCRIPTION_LAYER_OTHER, publisherId, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER_OTHER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testUnsubscribe_MultiplePublishers() {
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER_OTHER);
+ mSubscriber.unsubscribe(SUBSCRIPTION_LAYER);
+ assertSubscriptionState(3, SUBSCRIPTION_LAYER_OTHER);
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId2, PAYLOAD_OTHER);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testUnsubscribe_NotSubscribed() {
+ mSubscriber.unsubscribe(SUBSCRIPTION_LAYER);
+ assertNull(mPublisher.receiveSubscriptionState());
+
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testSubscribeToPublisher() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+ assertSubscriptionState(1,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId)));
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+ }
+
+ @Test
+ public void testSubscribeToPublisher_AfterPublish() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+
+ assertSubscriptionState(1,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId)));
+
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testSubscribeToPublisher_MultipleLayers() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER_OTHER, publisherId);
+
+ assertSubscriptionState(2,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId)),
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER_OTHER,
+ Collections.singleton(publisherId)));
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+
+ mPublisher.publish(SUBSCRIPTION_LAYER_OTHER, publisherId, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER_OTHER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testSubscribeToPublisher_MultiplePublishers() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+ assertSubscriptionState(1,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId)));
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId2, PAYLOAD_OTHER);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testSubscribeToPublisher_MultipleLayers_MultiplePublishers() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER_OTHER, publisherId2);
+ assertSubscriptionState(2,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId)),
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER_OTHER,
+ Collections.singleton(publisherId2)));
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD);
+
+ mPublisher.publish(SUBSCRIPTION_LAYER_OTHER, publisherId2, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER_OTHER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testSubscribeToPublisher_UnknownPublisher() {
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, UNKNOWN_PUBLISHER);
+
+ assertSubscriptionState(1,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER,
+ Collections.singleton(UNKNOWN_PUBLISHER)));
+ }
+
+ @Test
+ public void testSubscribeToPublisher_ClearCallback() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+ mSubscriber.clearVmsSubscriberClientCallback();
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testSubscribeToPublisher_NoCallback() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+
+ mSubscriber.clearVmsSubscriberClientCallback();
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+ }
+
+ @Test
+ public void testUnsubscribeToPublisher() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+ mSubscriber.unsubscribe(SUBSCRIPTION_LAYER, publisherId);
+ assertSubscriptionState(2, Collections.emptySet(), Collections.emptySet());
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testUnsubscribeToPublisher_MultipleLayers() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER_OTHER, publisherId);
+ mSubscriber.unsubscribe(SUBSCRIPTION_LAYER, publisherId);
+ assertSubscriptionState(3,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER_OTHER,
+ Collections.singleton(publisherId)));
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+
+ mPublisher.publish(SUBSCRIPTION_LAYER_OTHER, publisherId, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER_OTHER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testUnsubscribeToPublisher_MultiplePublishers() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+ int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
+
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId);
+ mSubscriber.subscribe(SUBSCRIPTION_LAYER, publisherId2);
+ mSubscriber.unsubscribe(SUBSCRIPTION_LAYER, publisherId);
+ assertSubscriptionState(3,
+ new VmsAssociatedLayer(SUBSCRIPTION_LAYER, Collections.singleton(publisherId2)));
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId2, PAYLOAD_OTHER);
+ assertDataMessage(SUBSCRIPTION_LAYER, PAYLOAD_OTHER);
+ }
+
+ @Test
+ public void testUnsubscribeToPublisher_NotSubscribed() {
+ int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
+
+ mSubscriber.unsubscribe(SUBSCRIPTION_LAYER, publisherId);
+ assertNull(mPublisher.receiveSubscriptionState());
+
+ mPublisher.publish(SUBSCRIPTION_LAYER, publisherId, PAYLOAD);
+ assertNull(mSubscriberClient.receiveMessage());
+ }
+
+ @Test
+ public void testUnsubscribeToPublisher_UnknownPublisher() {
+ mSubscriber.unsubscribe(SUBSCRIPTION_LAYER, UNKNOWN_PUBLISHER);
+ assertNull(mPublisher.receiveSubscriptionState());
+ }
+
+ private void assertLayerAvailability(int sequenceNumber,
+ VmsAssociatedLayer... associatedLayers) {
+ VmsAvailableLayers availableLayers = receiveWithSequence(
+ getMockSubscriberClient()::receiveLayerAvailability,
+ VmsAvailableLayers::getSequence,
+ sequenceNumber);
+ assertEquals(availableLayers, mSubscriber.getAvailableLayers());
+ assertEquals(new HashSet<>(Arrays.asList(associatedLayers)),
+ availableLayers.getAssociatedLayers());
+ }
+
+ private void assertSubscriptionState(int sequenceNumber, VmsLayer... layers) {
+ assertSubscriptionState(sequenceNumber, new HashSet<>(Arrays.asList(layers)),
+ Collections.emptySet());
+ }
+
+ private void assertSubscriptionState(int sequenceNumber,
+ VmsAssociatedLayer... associatedLayers) {
+ assertSubscriptionState(sequenceNumber, Collections.emptySet(),
+ new HashSet<>(Arrays.asList(associatedLayers)));
+ }
+
+ private void assertSubscriptionState(int sequenceNumber, Set<VmsLayer> layers,
+ Set<VmsAssociatedLayer> associatedLayers) {
+ VmsSubscriptionState subscriptionState = receiveWithSequence(
+ mPublisher::receiveSubscriptionState,
+ VmsSubscriptionState::getSequenceNumber,
+ sequenceNumber);
+ assertEquals(layers, subscriptionState.getLayers());
+ assertEquals(associatedLayers, subscriptionState.getAssociatedLayers());
+ }
+
+ private static <T> T receiveWithSequence(Supplier<T> supplierFunction,
+ ToIntFunction<T> sequenceNumberFn, int sequenceNumber) {
+ T obj = null;
+ for (int seq = 1; seq <= sequenceNumber; seq++) {
+ obj = supplierFunction.get();
+ assertNotNull(obj);
+ assertEquals(seq, sequenceNumberFn.applyAsInt(obj));
+ }
+ return obj;
+ }
+
+ private void assertDataMessage(VmsLayer layer, byte[] payload) {
+ Pair<VmsLayer, byte[]> message = mSubscriberClient.receiveMessage();
+ assertEquals(layer, message.first);
+ assertArrayEquals(payload, message.second);
}
}
diff --git a/tests/carservice_test/src/com/android/car/audio/AudioFocusTest.java b/tests/carservice_test/src/com/android/car/audio/AudioFocusTest.java
new file mode 100644
index 0000000..ff4c517
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/audio/AudioFocusTest.java
@@ -0,0 +1,488 @@
+/*
+ * 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.audio;
+
+import static org.junit.Assert.assertEquals;
+
+import android.media.AudioAttributes;
+import android.media.AudioFocusRequest;
+import android.media.AudioManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class AudioFocusTest {
+
+ private static final String TAG = "AudioFocusTest";
+
+ private static final int TEST_TIMING_TOLERANCE_MS = 100;
+
+ // ContextNumber.INVALID
+ private static final AudioAttributes ATTR_VIRTUAL_SOURCE = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_VIRTUAL_SOURCE)
+ .setContentType(AudioAttributes.USAGE_VIRTUAL_SOURCE)
+ .build();
+ // ContextNumber.MUSIC
+ private static final AudioAttributes ATTR_MEDIA = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_MEDIA)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+ .build();
+ // ContextNumber.NAVIGATION
+ private static final AudioAttributes ATTR_DRIVE_DIR = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+ .build();
+ // ContextNumber.VOICE_COMMAND
+ private static final AudioAttributes ATTR_A11Y = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+ .build();
+ // ContextNumber.CALL_RING
+ private static final AudioAttributes ATTR_RINGTONE = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build();
+ // ContextNumber.CALL
+ private static final AudioAttributes ATTR_VOICE_COM = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+ .build();
+ // ContextNumber.ALARM
+ private static final AudioAttributes ATTR_ALARM = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build();
+ // ContextNumber.NOTIFICATION
+ private static final AudioAttributes ATTR_NOTIFICATION = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build();
+ // ContextNumber.SYSTEM_SOUND
+ private static final AudioAttributes ATTR_A11Y_NOTIFICATION = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+ .build();
+
+ private AudioManager mAudioManager;
+
+ @Before
+ public void setUp() {
+ mAudioManager = new AudioManager(ApplicationProvider.getApplicationContext());
+ }
+
+ @Test
+ public void individualAttributeFocusRequest_focusRequestGranted() throws Exception {
+ // Make sure each usage is able to request and release audio focus individually
+ requestAndLoseFocusForAttribute(ATTR_VIRTUAL_SOURCE);
+ requestAndLoseFocusForAttribute(ATTR_MEDIA);
+ requestAndLoseFocusForAttribute(ATTR_DRIVE_DIR);
+ requestAndLoseFocusForAttribute(ATTR_A11Y);
+ requestAndLoseFocusForAttribute(ATTR_RINGTONE);
+ requestAndLoseFocusForAttribute(ATTR_VOICE_COM);
+ requestAndLoseFocusForAttribute(ATTR_ALARM);
+ requestAndLoseFocusForAttribute(ATTR_NOTIFICATION);
+ requestAndLoseFocusForAttribute(ATTR_A11Y_NOTIFICATION);
+ }
+
+ @Test
+ public void exclusiveInteractionsForFocusGain_requestGrantedAndFocusLossSent()
+ throws Exception {
+ // For each interaction the focus request is granted and on the second request
+ // focus lost is dispatched to the first focus listener
+
+ // Test Exclusive interactions with audio focus gain request without pause
+ // instead of ducking
+ testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN, false);
+ // Test Exclusive interactions with audio focus gain request with pause instead of ducking
+ testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN, true);
+ }
+
+ @Test
+ public void exclusiveInteractionsTransient_requestGrantedAndFocusLossSent()
+ throws Exception {
+ // For each interaction the focus request is granted and on the second request
+ // focus lost transient is dispatched to the first focus listener
+
+ // Test Exclusive interactions with audio focus gain transient request
+ // without pause instead of ducking
+ testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, false);
+ // Test Exclusive interactions with audio focus gain transient request
+ // with pause instead of ducking
+ testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, true);
+ }
+
+ @Test
+ public void exclusiveInteractionsTransientMayDuck_requestGrantedAndFocusLossSent()
+ throws Exception {
+ // For each interaction the focus request is granted and on the second request
+ // focus lost transient is dispatched to the first focus listener
+
+ // Test exclusive interactions with audio focus transient may duck focus request
+ // without pause instead of ducking
+ testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ false);
+ // Test exclusive interactions with audio focus transient may duck focus request
+ // with pause instead of ducking
+ testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ true);
+ }
+
+ @Test
+ public void rejectedInteractions_focusRequestRejected() throws Exception {
+ // Test different paired interaction between different usages
+ // for each interaction pair the first focus request will be granted but the second
+ // will be rejected
+ int interaction = CarAudioFocus.INTERACTION_REJECT;
+ int gain = AudioManager.AUDIOFOCUS_GAIN;
+ testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+ testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_MEDIA, interaction, gain, false);
+ testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_DRIVE_DIR, interaction, gain, false);
+ testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_A11Y, interaction, gain, false);
+ testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_RINGTONE, interaction, gain, false);
+ testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_VOICE_COM, interaction, gain, false);
+ testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_ALARM, interaction, gain, false);
+ testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_NOTIFICATION, interaction, gain, false);
+ testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_A11Y_NOTIFICATION, interaction, gain, false);
+
+ testInteraction(ATTR_MEDIA, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+
+ testInteraction(ATTR_DRIVE_DIR, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+
+ testInteraction(ATTR_A11Y, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+ testInteraction(ATTR_A11Y, ATTR_DRIVE_DIR, interaction, gain, false);
+ testInteraction(ATTR_A11Y, ATTR_NOTIFICATION, interaction, gain, false);
+ testInteraction(ATTR_A11Y, ATTR_A11Y_NOTIFICATION, interaction, gain, false);
+
+ testInteraction(ATTR_RINGTONE, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+ testInteraction(ATTR_RINGTONE, ATTR_MEDIA, interaction, gain, false);
+ testInteraction(ATTR_RINGTONE, ATTR_ALARM, interaction, gain, false);
+ testInteraction(ATTR_RINGTONE, ATTR_NOTIFICATION, interaction, gain, false);
+
+ testInteraction(ATTR_VOICE_COM, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+ testInteraction(ATTR_VOICE_COM, ATTR_MEDIA, interaction, gain, false);
+ testInteraction(ATTR_VOICE_COM, ATTR_A11Y, interaction, gain, false);
+
+ testInteraction(ATTR_ALARM, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+
+ testInteraction(ATTR_NOTIFICATION, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+
+ testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+ }
+
+ @Test
+ public void concurrentInteractionsFocusGain_requestGrantedAndFocusLossSent() throws Exception {
+ // Test concurrent interactions i.e. interactions that can
+ // potentially gain focus at the same time.
+ // For this test permanent focus gain is requested by two usages.
+ // The focus request will be granted for both and on the second focus request focus
+ // lost will dispatched to the first focus listener listener.
+ testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN, false);
+ }
+
+ @Test
+ public void concurrentInteractionsTransientGain_requestGrantedAndFocusLossTransientSent()
+ throws Exception {
+ // Test concurrent interactions i.e. interactions that can
+ // potentially gain focus at the same time.
+ // For this test permanent focus gain is requested by first usage and focus gain transient
+ // is requested by second usage.
+ // The focus request will be granted for both and on the second focus request focus
+ // lost transient will dispatched to the first focus listener listener.
+ testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, false);
+ // Repeat the test this time with pause for ducking on first listener
+ testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, true);
+ }
+
+ @Test
+ public void concurrentInteractionsTransientGainMayDuck_requestGrantedAndNoFocusLossSent()
+ throws Exception {
+ // Test concurrent interactions i.e. interactions that can
+ // potentially gain focus at the same time.
+ // For this test permanent focus gain is requested by first usage and focus gain transient
+ // may duck is requested by second usage.
+ // The focus request will be granted for both but no focus lost is sent to the first focus
+ // listener, as each usage actually has shared focus and should play at the same time.
+ testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+ // Test the same behaviour but this time with pause for ducking on the first focus listener
+ testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, true);
+ }
+
+ private void testConcurrentInteractions(int gain, boolean pauseForDucking)
+ throws Exception {
+ // Test paired concurrent interactions i.e. interactions that can
+ // potentially gain focus at the same time.
+ int interaction = CarAudioFocus.INTERACTION_CONCURRENT;
+ testInteraction(ATTR_MEDIA, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_MEDIA, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_MEDIA, ATTR_A11Y_NOTIFICATION, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_DRIVE_DIR, ATTR_MEDIA, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_DRIVE_DIR, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_DRIVE_DIR, ATTR_RINGTONE, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_DRIVE_DIR, ATTR_ALARM, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_DRIVE_DIR, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_DRIVE_DIR, ATTR_A11Y_NOTIFICATION, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_A11Y, ATTR_MEDIA, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_A11Y, ATTR_A11Y, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_RINGTONE, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_RINGTONE, ATTR_A11Y, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_RINGTONE, ATTR_RINGTONE, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_RINGTONE, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_VOICE_COM, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_VOICE_COM, ATTR_RINGTONE, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_VOICE_COM, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_VOICE_COM, ATTR_ALARM, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_VOICE_COM, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_ALARM, ATTR_MEDIA, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_ALARM, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_ALARM, ATTR_ALARM, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_ALARM, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_ALARM, ATTR_A11Y_NOTIFICATION, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_NOTIFICATION, ATTR_MEDIA, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_NOTIFICATION, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_NOTIFICATION, ATTR_ALARM, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_NOTIFICATION, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_NOTIFICATION, ATTR_A11Y_NOTIFICATION, interaction, gain,
+ pauseForDucking);
+
+
+ testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_MEDIA, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_ALARM, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_NOTIFICATION, interaction, gain,
+ pauseForDucking);
+ testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_A11Y_NOTIFICATION, interaction, gain,
+ pauseForDucking);
+ }
+
+ private void testExclusiveInteractions(int gain, boolean pauseForDucking)
+ throws Exception {
+
+ // Test exclusive interaction, interaction where each usage will not share focus with other
+ // another usage. As a result once focus is gained any current focus listener
+ // in this interaction will lose focus.
+ int interaction = CarAudioFocus.INTERACTION_EXCLUSIVE;
+ testInteraction(ATTR_MEDIA, ATTR_MEDIA, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_MEDIA, ATTR_A11Y, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_MEDIA, ATTR_RINGTONE, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_MEDIA, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_MEDIA, ATTR_ALARM, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_DRIVE_DIR, ATTR_A11Y, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_DRIVE_DIR, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_A11Y, ATTR_RINGTONE, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_A11Y, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_ALARM, ATTR_A11Y, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_ALARM, ATTR_RINGTONE, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_ALARM, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_NOTIFICATION, ATTR_A11Y, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_NOTIFICATION, ATTR_RINGTONE, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_NOTIFICATION, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
+
+ testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_A11Y, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_RINGTONE, interaction, gain, pauseForDucking);
+ testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
+ }
+
+
+ /**
+ * Test paired usage interactions with gainType and pause instead ducking
+ * @param attributes1 Attributes of the first usage (first focus requester) in the interaction
+ * @param attributes2 Attributes of the second usage (second focus requester) in the interaction
+ * @param interaction type of interaction {@link CarAudioFocus.INTERACTION_REJECT},
+ * {@link CarAudioFocus.INTERACTION_EXCLUSIVE}, {@link CarAudioFocus.INTERACTION_CONCURRENT}
+ * @param gainType Type of gain {@link AudioManager.AUDIOFOCUS_GAIN} ,
+ * {@link CarAudioFocus.AUDIOFOCUS_GAIN_TRANSIENT},
+ * {@link CarAudioFocus.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}
+ * @param pauseForDucking flag to indicate if the first focus listener should pause
+ * instead of ducking
+ * @throws Exception
+ */
+ private void testInteraction(AudioAttributes attributes1,
+ AudioAttributes attributes2,
+ int interaction,
+ int gainType,
+ boolean pauseForDucking) throws Exception {
+
+ final FocusChangeListener focusChangeListener1 = new FocusChangeListener();
+ final AudioFocusRequest audioFocusRequest1 = new AudioFocusRequest
+ .Builder(AudioManager.AUDIOFOCUS_GAIN)
+ .setAudioAttributes(attributes1)
+ .setOnAudioFocusChangeListener(focusChangeListener1)
+ .setForceDucking(false)
+ .setWillPauseWhenDucked(pauseForDucking)
+ .build();
+
+ final FocusChangeListener focusChangeListener2 = new FocusChangeListener();
+ final AudioFocusRequest audioFocusRequest2 = new AudioFocusRequest
+ .Builder(gainType)
+ .setAudioAttributes(attributes2)
+ .setOnAudioFocusChangeListener(focusChangeListener2)
+ .setForceDucking(false)
+ .build();
+
+ int expectedLoss = 0;
+
+ // Each focus gain type will return a different focus lost type
+ switch (gainType) {
+ case AudioManager.AUDIOFOCUS_GAIN:
+ expectedLoss = AudioManager.AUDIOFOCUS_LOSS;
+ break;
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+ expectedLoss = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+ break;
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+ expectedLoss = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+ // Note loss or gain will not be sent as both can live concurrently
+ if (interaction == CarAudioFocus.INTERACTION_CONCURRENT && !pauseForDucking) {
+ expectedLoss = AudioManager.AUDIOFOCUS_NONE;
+ }
+ break;
+ }
+
+ int secondRequestResultsExpected = AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+
+ if (interaction == CarAudioFocus.INTERACTION_REJECT) {
+ secondRequestResultsExpected = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+ }
+
+ int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest1);
+ String message = "Focus gain request failed for 1st "
+ + AudioAttributes.usageToString(attributes1.getUsage());
+ assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+
+
+ requestResult = mAudioManager.requestAudioFocus(audioFocusRequest2);
+ message = "Focus gain request failed for 2nd "
+ + AudioAttributes.usageToString(attributes2.getUsage());
+ assertEquals(message, secondRequestResultsExpected, requestResult);
+
+ // If the results is rejected for second one we only have to clean up first
+ // as the second focus request is rejected
+ if (interaction == CarAudioFocus.INTERACTION_REJECT) {
+ requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
+ message = "Focus loss request failed for 1st "
+ + AudioAttributes.usageToString(attributes1.getUsage());
+ assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+ }
+
+ // If exclusive we expect to lose focus on 1st one
+ // unless we have a concurrent interaction
+ if (interaction == CarAudioFocus.INTERACTION_EXCLUSIVE
+ || interaction == CarAudioFocus.INTERACTION_CONCURRENT) {
+ Thread.sleep(TEST_TIMING_TOLERANCE_MS);
+ message = "Focus change was not dispatched for 1st "
+ + AudioAttributes.usageToString(ATTR_MEDIA.getUsage());
+ assertEquals(message, expectedLoss,
+ focusChangeListener1.getFocusChangeAndReset());
+
+ requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest2);
+ message = "Focus loss request failed for 2nd "
+ + AudioAttributes.usageToString(ATTR_MEDIA.getUsage());
+ assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+
+ // If the loss was transient then we should have received back on 1st
+ if ((gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
+ || gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)) {
+
+ // Since ducking and concurrent can exist together
+ // this needs to be skipped as the focus lost is not sent
+ if (!(interaction == CarAudioFocus.INTERACTION_CONCURRENT
+ && gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)) {
+ Thread.sleep(TEST_TIMING_TOLERANCE_MS);
+ message = "Focus change was not dispatched for 1st "
+ + AudioAttributes.usageToString(ATTR_MEDIA.getUsage());
+ assertEquals(message, AudioManager.AUDIOFOCUS_GAIN,
+ focusChangeListener1.getFocusChangeAndReset());
+ }
+ // For concurrent focus interactions still needs to be released
+ message = "Focus loss request failed for 1st "
+ + AudioAttributes.usageToString(attributes1.getUsage());
+ requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
+ assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED,
+ requestResult);
+ }
+ }
+ }
+
+ /**
+ * Verifies usage can request audio focus and release it
+ * @param attribute usage attribute to request focus
+ * @throws Exception
+ */
+ private void requestAndLoseFocusForAttribute(AudioAttributes attribute) throws Exception {
+ final FocusChangeListener focusChangeListener = new FocusChangeListener();
+ final AudioFocusRequest audioFocusRequest = new AudioFocusRequest
+ .Builder(AudioManager.AUDIOFOCUS_GAIN)
+ .setAudioAttributes(attribute)
+ .setOnAudioFocusChangeListener(focusChangeListener)
+ .setForceDucking(false)
+ .build();
+
+
+ int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest);
+ String message = "Focus gain request failed for "
+ + AudioAttributes.usageToString(attribute.getUsage());
+ assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+
+ Thread.sleep(TEST_TIMING_TOLERANCE_MS);
+ // Verify no focus changed dispatched
+ message = "Focus change was dispatched for "
+ + AudioAttributes.usageToString(attribute.getUsage());
+ assertEquals(message, AudioManager.AUDIOFOCUS_NONE,
+ focusChangeListener.getFocusChangeAndReset());
+
+ requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest);
+ message = "Focus loss request failed for "
+ + AudioAttributes.usageToString(attribute.getUsage());
+ assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+ }
+
+ private static class FocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
+ private final Object mLock = new Object();
+ private int mFocusChange = AudioManager.AUDIOFOCUS_NONE;
+
+ int getFocusChangeAndReset() {
+ final int change;
+ synchronized (mLock) {
+ change = mFocusChange;
+ mFocusChange = AudioManager.AUDIOFOCUS_NONE;
+ }
+ return change;
+ }
+
+ @Override
+ public void onAudioFocusChange(int focusChange) {
+ synchronized (mLock) {
+ mFocusChange = focusChange;
+ }
+ }
+ }
+}
diff --git a/tests/carservice_test/src/com/android/car/vms/VmsBrokerServiceTest.java b/tests/carservice_test/src/com/android/car/vms/VmsBrokerServiceTest.java
new file mode 100644
index 0000000..5ce7df5
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/vms/VmsBrokerServiceTest.java
@@ -0,0 +1,197 @@
+/*
+ * 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.vms;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.vms.IVmsSubscriberClient;
+import android.car.vms.VmsLayer;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Process;
+
+import androidx.test.filters.MediumTest;
+
+import org.junit.Test;
+
+import java.util.function.IntSupplier;
+
+@MediumTest
+public class VmsBrokerServiceTest {
+
+ class MockIntProvider implements IntSupplier {
+ private int[] mInts;
+ private int mIdx;
+
+ MockIntProvider(int... ints) {
+ mInts = ints;
+ mIdx = 0;
+ }
+
+ public int getAsInt() {
+ int ret = mInts[mIdx];
+ mIdx++;
+ return ret;
+ }
+ }
+
+ /**
+ * Test that adding a subscriber to VmsBrokerService also keeps track of the package name for
+ * a given subscriber. Also checks that if we remove a dead subscriber, we no longer track the
+ * package name associated with it.
+ */
+ @Test
+ public void testAddSubscription() {
+ PackageManager packageManager = mock(PackageManager.class);
+ IVmsSubscriberClient subscriberClient = mock(IVmsSubscriberClient.class);
+ Binder binder = mock(Binder.class);
+ VmsLayer layer = mock(VmsLayer.class);
+ when(packageManager.getNameForUid(0)).thenReturn("test.package1");
+ when(subscriberClient.asBinder()).thenReturn(binder);
+
+ VmsBrokerService broker = new VmsBrokerService(packageManager, () -> 200, () -> 0);
+ broker.addSubscription(subscriberClient);
+ assertThat(broker.getPackageName(subscriberClient)).isEqualTo("test.package1");
+ broker.removeDeadSubscriber(subscriberClient);
+ assertThat(broker.getPackageName(subscriberClient)).isNull();
+ }
+
+ @Test
+ public void testAddSubscriptionLayer() {
+ PackageManager packageManager = mock(PackageManager.class);
+ IVmsSubscriberClient subscriberClient = mock(IVmsSubscriberClient.class);
+ Binder binder = mock(Binder.class);
+ VmsLayer layer = mock(VmsLayer.class);
+ when(packageManager.getNameForUid(0)).thenReturn("test.package2");
+ when(subscriberClient.asBinder()).thenReturn(binder);
+
+ VmsBrokerService broker = new VmsBrokerService(packageManager, () -> 200, () -> 0);
+ broker.addSubscription(subscriberClient, layer);
+ assertThat(broker.getPackageName(subscriberClient)).isEqualTo("test.package2");
+ broker.removeDeadSubscriber(subscriberClient);
+ assertThat(broker.getPackageName(subscriberClient)).isNull();
+ }
+
+ @Test
+ public void testAddSubscriptionLayerVersion() {
+ PackageManager packageManager = mock(PackageManager.class);
+ IVmsSubscriberClient subscriberClient = mock(IVmsSubscriberClient.class);
+ Binder binder = mock(Binder.class);
+ VmsLayer layer = mock(VmsLayer.class);
+ when(packageManager.getNameForUid(0)).thenReturn("test.package3");
+ when(subscriberClient.asBinder()).thenReturn(binder);
+
+ VmsBrokerService broker = new VmsBrokerService(packageManager, () -> 200, () -> 0);
+ broker.addSubscription(subscriberClient, layer, 1234);
+ assertThat(broker.getPackageName(subscriberClient)).isEqualTo("test.package3");
+ broker.removeDeadSubscriber(subscriberClient);
+ assertThat(broker.getPackageName(subscriberClient)).isNull();
+ }
+
+ @Test
+ public void testMultipleSubscriptionsSameClientCallsPackageManagerOnce() {
+ PackageManager packageManager = mock(PackageManager.class);
+ IVmsSubscriberClient subscriberClient = mock(IVmsSubscriberClient.class);
+ Binder binder = mock(Binder.class);
+ when(subscriberClient.asBinder()).thenReturn(binder);
+ when(packageManager.getNameForUid(0)).thenReturn("test.package3");
+
+ VmsBrokerService broker = new VmsBrokerService(packageManager, () -> 0, () -> 0);
+ broker.addSubscription(subscriberClient);
+ broker.addSubscription(subscriberClient);
+ // The second argument isn't necessary but is here for clarity.
+ verify(packageManager, times(1)).getNameForUid(0);
+ }
+
+ @Test
+ public void testUnknownPackageName() {
+ PackageManager packageManager = mock(PackageManager.class);
+ IVmsSubscriberClient subscriberClient = mock(IVmsSubscriberClient.class);
+ Binder binder = mock(Binder.class);
+ when(subscriberClient.asBinder()).thenReturn(binder);
+ when(packageManager.getNameForUid(0)).thenReturn(null);
+
+ VmsBrokerService broker = new VmsBrokerService(packageManager, () -> 0, () -> 0);
+ broker.addSubscription(subscriberClient);
+ assertThat(broker.getPackageName(subscriberClient)).isEqualTo(
+ VmsBrokerService.UNKNOWN_PACKAGE);
+ }
+
+ /**
+ * Tests that if the HAL is a subscriber, we record its package name as HalClient.
+ */
+ @Test
+ public void testAddingHalSubscriberSavesPackageName() {
+ PackageManager packageManager = mock(PackageManager.class);
+ IVmsSubscriberClient subscriberClient = mock(IVmsSubscriberClient.class);
+
+ VmsBrokerService broker = new VmsBrokerService(packageManager, () -> Process.myPid(),
+ () -> Process.SYSTEM_UID);
+ broker.addSubscription(subscriberClient);
+ assertThat(broker.getPackageName(subscriberClient)).isEqualTo(VmsBrokerService.HAL_CLIENT);
+ }
+
+ @Test
+ public void testMultipleSubscriptionsPackageManager() {
+ PackageManager packageManager = mock(PackageManager.class);
+
+ IVmsSubscriberClient subscriberClient1 = mock(IVmsSubscriberClient.class);
+ Binder binder1 = mock(Binder.class);
+ when(subscriberClient1.asBinder()).thenReturn(binder1);
+
+ IVmsSubscriberClient subscriberClient2 = mock(IVmsSubscriberClient.class);
+ Binder binder2 = mock(Binder.class);
+ when(subscriberClient2.asBinder()).thenReturn(binder2);
+
+ IVmsSubscriberClient subscriberClient3 = mock(IVmsSubscriberClient.class);
+ Binder binder3 = mock(Binder.class);
+ when(subscriberClient3.asBinder()).thenReturn(binder3);
+
+ // Tests a client with a different UID but the same package as subscriberClient1
+ IVmsSubscriberClient subscriberClient4 = mock(IVmsSubscriberClient.class);
+ Binder binder4 = mock(Binder.class);
+ when(subscriberClient4.asBinder()).thenReturn(binder4);
+
+ when(packageManager.getNameForUid(0)).thenReturn("test.package0");
+ when(packageManager.getNameForUid(1)).thenReturn("test.package1");
+ when(packageManager.getNameForUid(2)).thenReturn("test.package2");
+ when(packageManager.getNameForUid(3)).thenReturn("test.package0");
+
+ VmsBrokerService broker = new VmsBrokerService(packageManager, () -> 10,
+ new MockIntProvider(0, 1, 2, 3));
+
+ broker.addSubscription(subscriberClient1);
+ broker.addSubscription(subscriberClient2);
+ broker.addSubscription(subscriberClient3);
+ broker.addSubscription(subscriberClient4);
+
+ verify(packageManager).getNameForUid(0);
+ verify(packageManager).getNameForUid(1);
+ verify(packageManager).getNameForUid(2);
+ verify(packageManager).getNameForUid(3);
+
+ assertThat(broker.getPackageName(subscriberClient1)).isEqualTo("test.package0");
+ assertThat(broker.getPackageName(subscriberClient2)).isEqualTo("test.package1");
+ assertThat(broker.getPackageName(subscriberClient3)).isEqualTo("test.package2");
+ assertThat(broker.getPackageName(subscriberClient4)).isEqualTo("test.package0");
+ }
+}
diff --git a/tests/carservice_unit_test/Android.mk b/tests/carservice_unit_test/Android.mk
index b15dd41..6b715fc 100644
--- a/tests/carservice_unit_test/Android.mk
+++ b/tests/carservice_unit_test/Android.mk
@@ -53,9 +53,12 @@
car-service-lib-for-test \
com.android.car.test.utils \
junit \
- mockito-target-minus-junit4 \
+ mockito-target-inline-minus-junit4 \
frameworks-base-testutils \
truth-prebuilt
+# mockito-target-inline dependency
+LOCAL_JNI_SHARED_LIBRARIES := \
+ libdexmakerjvmtiagent \
include $(BUILD_PACKAGE)
diff --git a/tests/carservice_unit_test/AndroidManifest.xml b/tests/carservice_unit_test/AndroidManifest.xml
index 74f6aa1..e5e31bf 100644
--- a/tests/carservice_unit_test/AndroidManifest.xml
+++ b/tests/carservice_unit_test/AndroidManifest.xml
@@ -22,7 +22,8 @@
android:targetPackage="com.android.car.carservice_unittest"
android:label="Unit Tests for Car APIs"/>
- <application android:label="CarServiceUnitTest">
+ <application android:label="CarServiceUnitTest"
+ android:debuggable="true">
<uses-library android:name="android.test.runner" />
</application>
</manifest>
diff --git a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
index f653709..d08d32a 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
@@ -28,6 +28,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.car.drivingstate.CarDrivingStateEvent;
+import android.car.drivingstate.ICarDrivingStateChangeListener;
import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
import android.car.userlib.CarUserManagerHelper;
import android.content.Context;
@@ -73,6 +75,7 @@
* 2. {@link LocationManager} provides dummy {@link Location}s.
* 3. {@link CarUserManagerHelper} tells whether or not the system user is headless.
* 4. {@link SystemInterface} tells where to store system files.
+ * 5. {@link CarDrivingStateService} tells about driving state changes.
*/
@RunWith(AndroidJUnit4.class)
public class CarLocationServiceTest {
@@ -90,6 +93,8 @@
private CarUserManagerHelper mMockCarUserManagerHelper;
@Mock
private SystemInterface mMockSystemInterface;
+ @Mock
+ private CarDrivingStateService mMockCarDrivingStateService;
/**
* Initialize all of the objects with the @Mock annotation.
@@ -111,6 +116,9 @@
};
CarLocalServices.removeServiceForTest(SystemInterface.class);
CarLocalServices.addService(SystemInterface.class, mMockSystemInterface);
+ CarLocalServices.removeServiceForTest(CarDrivingStateService.class);
+ CarLocalServices.addService(CarDrivingStateService.class, mMockCarDrivingStateService);
+ when(mMockSystemInterface.getSystemCarDir()).thenReturn(mTempDirectory);
}
@After
@@ -142,10 +150,13 @@
*/
@Test
public void testRegistersToReceiveEvents() {
- ArgumentCaptor<IntentFilter> argument = ArgumentCaptor.forClass(IntentFilter.class);
+ ArgumentCaptor<IntentFilter> intentFilterArgument = ArgumentCaptor.forClass(
+ IntentFilter.class);
mCarLocationService.init();
- verify(mMockContext).registerReceiver(eq(mCarLocationService), argument.capture());
- IntentFilter intentFilter = argument.getValue();
+ verify(mMockContext).registerReceiver(eq(mCarLocationService),
+ intentFilterArgument.capture());
+ verify(mMockCarDrivingStateService).registerDrivingStateChangeListener(any());
+ IntentFilter intentFilter = intentFilterArgument.getValue();
assertEquals(3, intentFilter.countActions());
String[] actions = {intentFilter.getAction(0), intentFilter.getAction(1),
intentFilter.getAction(2)};
@@ -159,8 +170,10 @@
*/
@Test
public void testUnregistersEventReceivers() {
+ mCarLocationService.init();
mCarLocationService.release();
verify(mMockContext).unregisterReceiver(mCarLocationService);
+ verify(mMockCarDrivingStateService).unregisterDrivingStateChangeListener(any());
}
/**
@@ -177,7 +190,6 @@
ArgumentCaptor<Location> argument = ArgumentCaptor.forClass(Location.class);
when(mMockContext.getSystemService(Context.LOCATION_SERVICE))
.thenReturn(mMockLocationManager);
- when(mMockSystemInterface.getSystemCarDir()).thenReturn(mTempDirectory);
when(mMockLocationManager.injectLocation(argument.capture())).thenReturn(true);
when(mMockCarUserManagerHelper.isHeadlessSystemUser()).thenReturn(true);
@@ -292,10 +304,10 @@
/**
* Test that the {@link CarLocationService} stores the {@link LocationManager}'s last known
- * location upon power state-changed SUSPEND events.
+ * location upon power state-changed SHUTDOWN_PREPARE events.
*/
@Test
- public void testStoresLocationUponStateChanged() throws Exception {
+ public void testStoresLocationUponShutdownPrepare() throws Exception {
long currentTime = System.currentTimeMillis();
long elapsedTime = SystemClock.elapsedRealtimeNanos();
Location timbuktu = new Location(LocationManager.GPS_PROVIDER);
@@ -304,7 +316,6 @@
timbuktu.setAccuracy(13.75f);
timbuktu.setTime(currentTime);
timbuktu.setElapsedRealtimeNanos(elapsedTime);
- when(mMockSystemInterface.getSystemCarDir()).thenReturn(mTempDirectory);
when(mMockContext.getSystemService(Context.LOCATION_SERVICE))
.thenReturn(mMockLocationManager);
when(mMockLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER))
@@ -326,7 +337,7 @@
* Test that the {@link CarLocationService} does not throw an exception on SUSPEND_EXIT events.
*/
@Test
- public void testDoesNotThrowExceptionUponStateChanged() {
+ public void testDoesNotThrowExceptionUponPowerStateChanged() {
try {
mCarLocationService.onStateChanged(CarPowerStateListener.SUSPEND_ENTER, null);
mCarLocationService.onStateChanged(CarPowerStateListener.SUSPEND_EXIT, null);
@@ -361,36 +372,86 @@
*/
@Test
public void testDeletesCacheFileWhenLocationIsDisabled() throws Exception {
+ writeCacheFile("{\"provider\":\"latitude\":16.7666,\"longitude\": \"accuracy\":1.0}");
when(mMockContext.getSystemService(Context.LOCATION_SERVICE))
.thenReturn(mMockLocationManager);
when(mMockLocationManager.isLocationEnabled()).thenReturn(false);
mCarLocationService.init();
+ assertTrue(getLocationCacheFile().exists());
+
mCarLocationService.onReceive(mMockContext,
new Intent(LocationManager.MODE_CHANGED_ACTION));
- mLatch.await();
+
verify(mMockLocationManager, times(1)).isLocationEnabled();
assertFalse(getLocationCacheFile().exists());
}
/**
+ * Test that the {@link CarLocationService} deletes location_cache.json when the system resumes
+ * from suspend-to-ram.
+ */
+ @Test
+ public void testDeletesCacheFileUponSuspendExit() throws Exception {
+ when(mMockContext.getSystemService(Context.LOCATION_SERVICE))
+ .thenReturn(mMockLocationManager);
+ when(mMockLocationManager.isLocationEnabled()).thenReturn(false);
+ mCarLocationService.init();
+ CompletableFuture<Void> future = new CompletableFuture<>();
+ mCarLocationService.onStateChanged(CarPowerStateListener.SUSPEND_EXIT, future);
+ assertTrue(future.isDone());
+ verify(mMockLocationManager, times(0)).isLocationEnabled();
+ assertFalse(getLocationCacheFile().exists());
+ }
+
+ /**
* Test that the {@link CarLocationService} deletes location_cache.json when the GPS location
* provider is disabled.
*/
@Test
public void testDeletesCacheFileWhenTheGPSProviderIsDisabled() throws Exception {
+ writeCacheFile("{\"provider\":\"latitude\":16.7666,\"longitude\": \"accuracy\":1.0}");
when(mMockContext.getSystemService(Context.LOCATION_SERVICE))
.thenReturn(mMockLocationManager);
when(mMockLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)).thenReturn(
false);
mCarLocationService.init();
+ assertTrue(getLocationCacheFile().exists());
+
mCarLocationService.onReceive(mMockContext,
new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
- mLatch.await();
+
verify(mMockLocationManager, times(1))
.isProviderEnabled(LocationManager.GPS_PROVIDER);
assertFalse(getLocationCacheFile().exists());
}
+ /**
+ * Test that the {@link CarLocationService} deletes location_cache.json when the car enters a
+ * moving driving state.
+ */
+ @Test
+ public void testDeletesCacheFileWhenDrivingStateBecomesMoving() throws Exception {
+ writeCacheFile("{\"provider\":\"latitude\":16.7666,\"longitude\": \"accuracy\":1.0}");
+ when(mMockContext.getSystemService(Context.LOCATION_SERVICE))
+ .thenReturn(mMockLocationManager);
+ when(mMockLocationManager.isLocationEnabled()).thenReturn(false);
+ mCarLocationService.init();
+ ArgumentCaptor<ICarDrivingStateChangeListener> changeListenerArgument =
+ ArgumentCaptor.forClass(ICarDrivingStateChangeListener.class);
+ verify(mMockCarDrivingStateService).registerDrivingStateChangeListener(
+ changeListenerArgument.capture());
+ ICarDrivingStateChangeListener changeListener = changeListenerArgument.getValue();
+ assertTrue(getLocationCacheFile().exists());
+
+ changeListener.onDrivingStateChanged(
+ new CarDrivingStateEvent(CarDrivingStateEvent.DRIVING_STATE_MOVING,
+ SystemClock.elapsedRealtimeNanos()));
+
+ verify(mMockLocationManager, times(0)).isLocationEnabled();
+ verify(mMockCarDrivingStateService, times(1)).unregisterDrivingStateChangeListener(any());
+ assertFalse(getLocationCacheFile().exists());
+ }
+
private void writeCacheFile(String json) throws IOException {
FileOutputStream fos = new FileOutputStream(getLocationCacheFile());
fos.write(json.getBytes());
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java b/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java
index 6e0c2fe..2c63ef5 100644
--- a/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java
@@ -16,6 +16,8 @@
package com.android.car;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
@@ -52,12 +54,16 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
@SmallTest
public class VmsPublisherServiceTest {
@@ -66,8 +72,14 @@
private static final VmsLayersOffering OFFERING = new VmsLayersOffering(Collections.emptySet(),
54321);
private static final VmsLayer LAYER = new VmsLayer(1, 2, 3);
+ private static final VmsLayer LAYER2 = new VmsLayer(2, 2, 8);
+ private static final VmsLayer LAYER3 = new VmsLayer(3, 2, 8);
+ private static final VmsLayer LAYER4 = new VmsLayer(4, 2, 8);
+
private static final int PUBLISHER_ID = 54321;
private static final byte[] PAYLOAD = new byte[]{1, 2, 3, 4};
+ private static final byte[] PAYLOAD2 = new byte[]{1, 2, 3, 4, 5, 6};
+ private static final byte[] PAYLOAD3 = new byte[]{10, 12, 93, 4, 5, 6, 1, 1, 1};
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -84,6 +96,10 @@
private IVmsSubscriberClient mSubscriberClient;
@Mock
private IVmsSubscriberClient mSubscriberClient2;
+ @Mock
+ private IVmsSubscriberClient mThrowingSubscriberClient;
+ @Mock
+ private IVmsSubscriberClient mThrowingSubscriberClient2;
private VmsPublisherService mPublisherService;
private MockPublisherClient mPublisherClient;
@@ -96,6 +112,7 @@
mPublisherClient2 = new MockPublisherClient();
when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER, PUBLISHER_ID))
.thenReturn(new HashSet<>(Arrays.asList(mSubscriberClient, mSubscriberClient2)));
+
}
@Test
@@ -175,6 +192,15 @@
}
@Test
+ public void testPublishNullLayerAndNullPayload() throws Exception {
+ mPublisherService.onClientConnected("SomeClient", mPublisherClient.asBinder());
+
+ // We just want to ensure that no exceptions are thrown here.
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, null, PUBLISHER_ID,
+ null);
+ }
+
+ @Test
public void testPublish_ClientError() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient.asBinder());
doThrow(new RemoteException()).when(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD);
@@ -274,6 +300,341 @@
}
@Test
+ public void testDump_getPacketCount() throws Exception {
+ mPublisherService.onClientConnected("SomeClient", mPublisherClient.asBinder());
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintWriter printWriter = new PrintWriter(outputStream);
+
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherService.dump(printWriter);
+
+ printWriter.flush();
+ String dumpString = outputStream.toString();
+ String expectedPacketCountString = String.format(VmsPublisherService.PACKET_COUNT_FORMAT,
+ LAYER, 1L);
+ String expectedPacketSizeString = String.format(VmsPublisherService.PACKET_SIZE_FORMAT,
+ LAYER, PAYLOAD.length);
+ assertThat(dumpString.contains(expectedPacketCountString)).isTrue();
+ assertThat(dumpString.contains(expectedPacketSizeString)).isTrue();
+ }
+
+ @Test
+ public void testDump_getPacketCounts() throws Exception {
+ mPublisherService.onClientConnected("SomeClient", mPublisherClient.asBinder());
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintWriter printWriter = new PrintWriter(outputStream);
+
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER2, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
+ PAYLOAD2);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER3, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
+ PAYLOAD3);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
+ PAYLOAD3);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER2, PUBLISHER_ID,
+ PAYLOAD3);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
+ PAYLOAD3);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER3, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherService.dump(printWriter);
+
+ printWriter.flush();
+ String dumpString = outputStream.toString();
+
+ // LAYER called 6 times with PAYLOAD 2 times, PAYLOAD2 1 time, PAYLOAD3 3 times
+ String expectedPacketCountString1 = String.format(VmsPublisherService.PACKET_COUNT_FORMAT,
+ LAYER, 6L);
+ String expectedPacketSizeString1 = String.format(VmsPublisherService.PACKET_SIZE_FORMAT,
+ LAYER, 2 * PAYLOAD.length + PAYLOAD2.length + 3 * PAYLOAD3.length);
+
+ // LAYER2 called 2 times with PAYLOAD 1 time, PAYLOAD2 0 time, PAYLOAD3 1 times
+ String expectedPacketCountString2 = String.format(VmsPublisherService.PACKET_COUNT_FORMAT,
+ LAYER2, 2L);
+ String expectedPacketSizeString2 = String.format(VmsPublisherService.PACKET_SIZE_FORMAT,
+ LAYER2, PAYLOAD.length + PAYLOAD3.length);
+
+ // LAYER3 called 2 times with PAYLOAD 2 times, PAYLOAD2 0 time, PAYLOAD3 0 times
+ String expectedPacketCountString3 = String.format(VmsPublisherService.PACKET_COUNT_FORMAT,
+ LAYER3, 2L);
+ String expectedPacketSizeString3 = String.format(VmsPublisherService.PACKET_SIZE_FORMAT,
+ LAYER3, 2 * PAYLOAD.length);
+
+ assertThat(dumpString.contains(expectedPacketCountString1)).isTrue();
+ assertThat(dumpString.contains(expectedPacketSizeString1)).isTrue();
+ assertThat(dumpString.contains(expectedPacketCountString2)).isTrue();
+ assertThat(dumpString.contains(expectedPacketSizeString2)).isTrue();
+ assertThat(dumpString.contains(expectedPacketCountString3)).isTrue();
+ assertThat(dumpString.contains(expectedPacketSizeString3)).isTrue();
+ }
+
+ @Test
+ public void testDumpNoListeners_getPacketFailureCount() throws Exception {
+ mPublisherService.onClientConnected("SomeClient", mPublisherClient.asBinder());
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintWriter printWriter = new PrintWriter(outputStream);
+
+ // Layer 2 has no listeners and should therefore result in a packet failure to be recorded.
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER2, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherService.dump(printWriter);
+
+ printWriter.flush();
+ String dumpString = outputStream.toString();
+
+ String expectedPacketFailureString = String.format(
+ VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT,
+ LAYER2, "SomeClient", "", 1L);
+ String expectedPacketFailureSizeString = String.format(
+ VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT,
+ LAYER2, "SomeClient", "", PAYLOAD.length);
+
+ assertThat(dumpString.contains(expectedPacketFailureString)).isTrue();
+ assertThat(dumpString.contains(expectedPacketFailureSizeString)).isTrue();
+ }
+
+ @Test
+ public void testDumpNoListeners_getPacketFailureCounts() throws Exception {
+ // LAYER2 and LAYER3 both have no listeners
+ when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER2, PUBLISHER_ID))
+ .thenReturn(new HashSet<>());
+ when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER3, PUBLISHER_ID))
+ .thenReturn(new HashSet<>());
+
+ mPublisherService.onClientConnected("SomeClient", mPublisherClient.asBinder());
+ mPublisherService.onClientConnected("SomeClient2", mPublisherClient2.asBinder());
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintWriter printWriter = new PrintWriter(outputStream);
+
+ // Layer 2 has no listeners and should therefore result in a packet failure to be recorded.
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER2, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient2.mPublisherService.publish(mPublisherClient2.mToken, LAYER3, PUBLISHER_ID,
+ PAYLOAD);
+
+ mPublisherService.dump(printWriter);
+
+ printWriter.flush();
+ String dumpString = outputStream.toString();
+
+ String expectedPacketFailureString = String.format(
+ VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT,
+ LAYER2, "SomeClient", "", 1L);
+ String expectedPacketFailureString2 = String.format(
+ VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT,
+ LAYER3, "SomeClient2", "", 1L);
+ String expectedPacketFailureSizeString = String.format(
+ VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT,
+ LAYER2, "SomeClient", "", PAYLOAD.length);
+ String expectedPacketFailureSizeString2 = String.format(
+ VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT,
+ LAYER3, "SomeClient2", "", PAYLOAD.length);
+
+ assertThat(dumpString.contains(expectedPacketFailureString)).isTrue();
+ assertThat(dumpString.contains(expectedPacketFailureSizeString)).isTrue();
+ assertThat(dumpString.contains(expectedPacketFailureString2)).isTrue();
+ assertThat(dumpString.contains(expectedPacketFailureSizeString2)).isTrue();
+ }
+
+ @Test
+ public void testDumpRemoteException_getPacketFailureCount() throws Exception {
+ // The listener on LAYER3 will throw on LAYER3 and PAYLOAD
+ Mockito.doThrow(new RemoteException()).when(mThrowingSubscriberClient).onVmsMessageReceived(
+ LAYER3, PAYLOAD);
+ when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER3, PUBLISHER_ID))
+ .thenReturn(new HashSet<>(Arrays.asList(mThrowingSubscriberClient)));
+ when(mBrokerService.getPackageName(mThrowingSubscriberClient)).thenReturn("Thrower");
+
+ mPublisherService.onClientConnected("SomeClient", mPublisherClient.asBinder());
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintWriter printWriter = new PrintWriter(outputStream);
+
+ // Layer 2 has no listeners and should therefore result in a packet failure to be recorded.
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER3, PUBLISHER_ID,
+ PAYLOAD);
+
+ mPublisherService.dump(printWriter);
+
+ printWriter.flush();
+ String dumpString = outputStream.toString();
+
+ String expectedPacketFailureString = String.format(
+ VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT,
+ LAYER3, "SomeClient", "Thrower", 1L);
+ String expectedPacketFailureSizeString = String.format(
+ VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT,
+ LAYER3, "SomeClient", "Thrower", PAYLOAD.length);
+
+ assertThat(dumpString.contains(expectedPacketFailureString)).isTrue();
+ assertThat(dumpString.contains(expectedPacketFailureSizeString)).isTrue();
+ }
+
+ @Test
+ public void testDumpRemoteException_getPacketFailureCounts() throws Exception {
+ // The listeners will throw on LAYER3 or LAYER4 and PAYLOAD
+ Mockito.doThrow(new RemoteException()).when(mThrowingSubscriberClient).onVmsMessageReceived(
+ LAYER3, PAYLOAD);
+ Mockito.doThrow(new RemoteException()).when(mThrowingSubscriberClient).onVmsMessageReceived(
+ LAYER4, PAYLOAD);
+ Mockito.doThrow(new RemoteException()).when(
+ mThrowingSubscriberClient2).onVmsMessageReceived(LAYER3, PAYLOAD);
+ Mockito.doThrow(new RemoteException()).when(
+ mThrowingSubscriberClient2).onVmsMessageReceived(LAYER4, PAYLOAD);
+
+ when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER3, PUBLISHER_ID))
+ .thenReturn(new HashSet<>(
+ Arrays.asList(mThrowingSubscriberClient, mThrowingSubscriberClient2)));
+ when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER4, PUBLISHER_ID))
+ .thenReturn(new HashSet<>(
+ Arrays.asList(mThrowingSubscriberClient, mThrowingSubscriberClient2)));
+
+ when(mBrokerService.getPackageName(mThrowingSubscriberClient)).thenReturn("Thrower");
+ when(mBrokerService.getPackageName(mThrowingSubscriberClient2)).thenReturn("Thrower2");
+
+ mPublisherService.onClientConnected("SomeClient", mPublisherClient.asBinder());
+ mPublisherService.onClientConnected("SomeClient2", mPublisherClient2.asBinder());
+
+ // Layer 2 has no listeners and should therefore result in a packet failure to be recorded.
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER3, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER3, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER4, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER4, PUBLISHER_ID,
+ PAYLOAD);
+
+ mPublisherClient2.mPublisherService.publish(mPublisherClient2.mToken, LAYER3, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient2.mPublisherService.publish(mPublisherClient2.mToken, LAYER3, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient2.mPublisherService.publish(mPublisherClient2.mToken, LAYER4, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient2.mPublisherService.publish(mPublisherClient2.mToken, LAYER4, PUBLISHER_ID,
+ PAYLOAD);
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintWriter printWriter = new PrintWriter(outputStream);
+ mPublisherService.dump(printWriter);
+
+ printWriter.flush();
+ String dumpString = outputStream.toString();
+
+ List<String> expectedStrings = Arrays.asList(
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER3, "SomeClient",
+ "Thrower", 2L),
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER3, "SomeClient",
+ "Thrower2", 2L),
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER4, "SomeClient",
+ "Thrower", 2L),
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER4, "SomeClient",
+ "Thrower2", 2L),
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER3,
+ "SomeClient2",
+ "Thrower", 2L),
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER3,
+ "SomeClient2",
+ "Thrower2", 2L),
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER4,
+ "SomeClient2",
+ "Thrower", 2L),
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER4,
+ "SomeClient2",
+ "Thrower2", 2L),
+
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER3, "SomeClient",
+ "Thrower", 2 * PAYLOAD.length),
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER3, "SomeClient",
+ "Thrower2", 2 * PAYLOAD.length),
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER4, "SomeClient",
+ "Thrower", 2 * PAYLOAD.length),
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER4, "SomeClient",
+ "Thrower2", 2 * PAYLOAD.length),
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER3, "SomeClient2",
+ "Thrower", 2 * PAYLOAD.length),
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER3, "SomeClient2",
+ "Thrower2", 2 * PAYLOAD.length),
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER4, "SomeClient2",
+ "Thrower", 2 * PAYLOAD.length),
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER4, "SomeClient2",
+ "Thrower2", 2 * PAYLOAD.length));
+
+ for (String expected : expectedStrings) {
+ assertThat(dumpString.contains(expected)).isTrue();
+ }
+ }
+
+ @Test
+ public void testDump_getAllMetrics() throws Exception {
+
+ // LAYER3 has no subscribers
+ when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER3, PUBLISHER_ID))
+ .thenReturn(new HashSet<>(Arrays.asList()));
+
+ // LAYER4 has a subscriber that will always throw
+ Mockito.doThrow(new RemoteException()).when(mThrowingSubscriberClient).onVmsMessageReceived(
+ LAYER4, PAYLOAD);
+
+ when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER4, PUBLISHER_ID))
+ .thenReturn(new HashSet<>(
+ Arrays.asList(mThrowingSubscriberClient)));
+
+ when(mBrokerService.getPackageName(mThrowingSubscriberClient)).thenReturn("Thrower");
+
+ mPublisherService.onClientConnected("SomeClient", mPublisherClient.asBinder());
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
+ PAYLOAD);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
+ PAYLOAD2);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER3, PUBLISHER_ID,
+ PAYLOAD3);
+ mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER4, PUBLISHER_ID,
+ PAYLOAD);
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintWriter printWriter = new PrintWriter(outputStream);
+ mPublisherService.dump(printWriter);
+
+ printWriter.flush();
+ String dumpString = outputStream.toString();
+
+ List<String> expectedStrings = Arrays.asList(
+ String.format(VmsPublisherService.PACKET_COUNT_FORMAT, LAYER, 2),
+ String.format(VmsPublisherService.PACKET_COUNT_FORMAT, LAYER3, 1),
+ String.format(VmsPublisherService.PACKET_COUNT_FORMAT, LAYER4, 1),
+ String.format(VmsPublisherService.PACKET_SIZE_FORMAT, LAYER,
+ PAYLOAD.length + PAYLOAD2.length),
+ String.format(VmsPublisherService.PACKET_SIZE_FORMAT, LAYER3, PAYLOAD3.length),
+ String.format(VmsPublisherService.PACKET_SIZE_FORMAT, LAYER4, PAYLOAD.length),
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER3, "SomeClient",
+ "",
+ 1),
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER3, "SomeClient",
+ "",
+ PAYLOAD3.length),
+ String.format(VmsPublisherService.PACKET_FAILURE_COUNT_FORMAT, LAYER4, "SomeClient",
+ "Thrower", 1),
+ String.format(VmsPublisherService.PACKET_FAILURE_SIZE_FORMAT, LAYER4, "SomeClient",
+ "Thrower", PAYLOAD.length)
+ );
+
+ for (String expected : expectedStrings) {
+ assertThat(dumpString.contains(expected)).isTrue();
+ }
+ }
+
+
+ @Test
public void testRelease() {
mPublisherService.release();
verify(mClientManager).unregisterConnectionListener(mPublisherService);
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
index 32f8e1d..5cce922 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
@@ -181,6 +181,28 @@
assertThat(event.getRepeatCount()).isEqualTo(0);
}
+ /**
+ * Test for handling rotary knob event.
+ */
+ @Test
+ public void handlesRepeatedKeyWithIndents() {
+ subscribeListener();
+ KeyEvent event = dispatchSingleEventWithIndents(KeyEvent.KEYCODE_VOLUME_UP, 5);
+ assertThat(event.getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+ assertThat(event.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_VOLUME_UP);
+ assertThat(event.getEventTime()).isEqualTo(0L);
+ assertThat(event.getDownTime()).isEqualTo(0L);
+ assertThat(event.getRepeatCount()).isEqualTo(4);
+
+ when(mUptimeSupplier.getAsLong()).thenReturn(5L);
+ event = dispatchSingleEventWithIndents(KeyEvent.KEYCODE_VOLUME_UP, 5);
+ assertThat(event.getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+ assertThat(event.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_VOLUME_UP);
+ assertThat(event.getEventTime()).isEqualTo(5L);
+ assertThat(event.getDownTime()).isEqualTo(5L);
+ assertThat(event.getRepeatCount()).isEqualTo(9);
+ }
+
@Test
public void handlesKeyUp_withoutKeyDown() {
subscribeListener();
@@ -237,4 +259,25 @@
reset(mInputListener);
return captor.getValue();
}
-}
+
+ private VehiclePropValue makeKeyPropValueWithIndents(int code, int indents) {
+ VehiclePropValue v = new VehiclePropValue();
+ v.prop = VehicleProperty.HW_KEY_INPUT;
+ // Only Key.down can have indents.
+ v.value.int32Values.add(VehicleHwKeyInputAction.ACTION_DOWN);
+ v.value.int32Values.add(code);
+ v.value.int32Values.add(DISPLAY);
+ v.value.int32Values.add(indents);
+ return v;
+ }
+
+ private KeyEvent dispatchSingleEventWithIndents(int code, int indents) {
+ ArgumentCaptor<KeyEvent> captor = ArgumentCaptor.forClass(KeyEvent.class);
+ reset(mInputListener);
+ mInputHalService.handleHalEvents(
+ ImmutableList.of(makeKeyPropValueWithIndents(code, indents)));
+ verify(mInputListener).onKeyEvent(captor.capture(), eq(DISPLAY));
+ reset(mInputListener);
+ return captor.getValue();
+ }
+}
\ No newline at end of file
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
index baaab26..f42c52a 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
@@ -37,14 +37,13 @@
import android.os.Binder;
import android.os.IBinder;
-import androidx.test.runner.AndroidJUnit4;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -54,8 +53,8 @@
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
-@RunWith(AndroidJUnit4.class)
public class VmsHalServiceTest {
private static final int LAYER_TYPE = 1;
private static final int LAYER_SUBTYPE = 2;
@@ -64,6 +63,8 @@
private static final int PUBLISHER_ID = 12345;
private static final byte[] PAYLOAD = new byte[]{1, 2, 3, 4};
private static final List<Byte> PAYLOAD_AS_LIST = Arrays.asList(new Byte[]{1, 2, 3, 4});
+ private static final int CORE_ID = 54321;
+ private static final int CLIENT_ID = 98765;
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
@@ -73,6 +74,12 @@
private IVmsPublisherService mPublisherService;
@Mock
private IVmsSubscriberService mSubscriberService;
+ @Mock
+ private Consumer<IBinder> mPublisherOnHalConnected;
+ @Mock
+ private Runnable mPublisherOnHalDisconnected;
+ @Mock
+ private Consumer<IVmsSubscriberClient> mSubscriberOnHalDisconnected;
private IBinder mToken;
private VmsHalService mHalService;
@@ -81,12 +88,10 @@
@Before
public void setUp() throws Exception {
- mHalService = new VmsHalService(mVehicleHal);
- mHalService.setVmsSubscriberService(mSubscriberService);
-
- mToken = new Binder();
- mPublisherClient = IVmsPublisherClient.Stub.asInterface(mHalService.getPublisherClient());
- mPublisherClient.setVmsPublisherService(mToken, mPublisherService);
+ mHalService = new VmsHalService(mVehicleHal, () -> (long) CORE_ID);
+ mHalService.setPublisherConnectionCallbacks(
+ mPublisherOnHalConnected, mPublisherOnHalDisconnected);
+ mHalService.setVmsSubscriberService(mSubscriberService, mSubscriberOnHalDisconnected);
VehiclePropConfig propConfig = new VehiclePropConfig();
propConfig.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
@@ -97,16 +102,68 @@
mHalService.init();
waitForHandlerCompletion();
+ // Verify START_SESSION message was sent
+ InOrder initOrder =
+ Mockito.inOrder(mPublisherOnHalConnected, mSubscriberService, mVehicleHal);
+ initOrder.verify(mVehicleHal).subscribeProperty(mHalService,
+ VehicleProperty.VEHICLE_MAP_SERVICE);
+ initOrder.verify(mVehicleHal).set(createHalMessage(
+ VmsMessageType.START_SESSION, // Message type
+ CORE_ID, // Core ID
+ -1)); // Client ID (unknown)
+
+ // Verify no more interections until handshake received
+ initOrder.verifyNoMoreInteractions();
+
+ // Send START_SESSION response from client
+ sendHalMessage(createHalMessage(
+ VmsMessageType.START_SESSION, // Message type
+ 0, // Core ID (unknown)
+ CLIENT_ID // Client ID
+ ));
+ waitForHandlerCompletion();
+
+ // Verify client is marked as connected
+ ArgumentCaptor<IBinder> publisherCaptor = ArgumentCaptor.forClass(IBinder.class);
+ initOrder.verify(mPublisherOnHalConnected).accept(publisherCaptor.capture());
+ mPublisherClient = IVmsPublisherClient.Stub.asInterface(publisherCaptor.getValue());
+
+ mToken = new Binder();
+ mPublisherClient.setVmsPublisherService(mToken, mPublisherService);
+
ArgumentCaptor<IVmsSubscriberClient> subscriberCaptor = ArgumentCaptor.forClass(
IVmsSubscriberClient.class);
- verify(mSubscriberService).addVmsSubscriberToNotifications(subscriberCaptor.capture());
+ initOrder.verify(mSubscriberService).addVmsSubscriberToNotifications(
+ subscriberCaptor.capture());
mSubscriberClient = subscriberCaptor.getValue();
- reset(mSubscriberService);
- verify(mVehicleHal).set(createHalMessage(
+
+ initOrder.verify(mSubscriberService).getAvailableLayers();
+ initOrder.verify(mVehicleHal).set(createHalMessage(
VmsMessageType.AVAILABILITY_CHANGE, // Message type
0, // Sequence number
0)); // # of associated layers
- reset(mVehicleHal);
+
+ initOrder.verifyNoMoreInteractions();
+ reset(mPublisherOnHalConnected, mSubscriberService, mVehicleHal);
+ }
+
+ @Test
+ public void testCoreId_IntegerOverflow() throws Exception {
+ mHalService = new VmsHalService(mVehicleHal, () -> (long) Integer.MAX_VALUE + CORE_ID);
+
+ VehiclePropConfig propConfig = new VehiclePropConfig();
+ propConfig.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
+ mHalService.takeSupportedProperties(Collections.singleton(propConfig));
+
+ when(mSubscriberService.getAvailableLayers()).thenReturn(
+ new VmsAvailableLayers(Collections.emptySet(), 0));
+ mHalService.init();
+ waitForHandlerCompletion();
+
+ verify(mVehicleHal).set(createHalMessage(
+ VmsMessageType.START_SESSION, // Message type
+ CORE_ID, // Core ID
+ -1)); // Client ID (unknown)
}
@Test
@@ -506,6 +563,40 @@
}
/**
+ * START_SESSION message format:
+ * <ul>
+ * <li>Message type
+ * <li>Core ID
+ * <li>Client ID
+ * </ul>
+ */
+ @Test
+ public void testHandleStartSessionEvent() throws Exception {
+ when(mSubscriberService.getAvailableLayers()).thenReturn(
+ new VmsAvailableLayers(Collections.emptySet(), 5));
+
+ VehiclePropValue request = createHalMessage(
+ VmsMessageType.START_SESSION, // Message type
+ 0, // Core ID (unknown)
+ CLIENT_ID // Client ID
+ );
+
+ VehiclePropValue response = createHalMessage(
+ VmsMessageType.START_SESSION, // Message type
+ CORE_ID, // Core ID
+ CLIENT_ID // Client ID
+ );
+
+ sendHalMessage(request);
+ InOrder inOrder = Mockito.inOrder(mVehicleHal);
+ inOrder.verify(mVehicleHal).set(response);
+ inOrder.verify(mVehicleHal).set(createHalMessage(
+ VmsMessageType.AVAILABILITY_CHANGE, // Message type
+ 5, // Sequence number
+ 0)); // # of associated layers
+ }
+
+ /**
* AVAILABILITY_CHANGE message format:
* <ul>
* <li>Message type
@@ -865,9 +956,7 @@
private void waitForHandlerCompletion() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
- mHalService.getHandler().post(() -> {
- latch.countDown();
- });
+ mHalService.getHandler().post(latch::countDown);
latch.await(5, TimeUnit.SECONDS);
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/trust/CarTrustAgentEnrollmentServiceTest.java b/tests/carservice_unit_test/src/com/android/car/trust/CarTrustAgentEnrollmentServiceTest.java
new file mode 100644
index 0000000..8982c1e
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/trust/CarTrustAgentEnrollmentServiceTest.java
@@ -0,0 +1,257 @@
+/*
+ * 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.car.encryptionrunner.DummyEncryptionRunner;
+import android.car.encryptionrunner.EncryptionRunnerFactory;
+import android.car.encryptionrunner.HandshakeMessage;
+import android.car.trust.TrustedDeviceInfo;
+import android.car.userlib.CarUserManagerHelper;
+import android.content.Context;
+import android.os.RemoteException;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.car.Utils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.UUID;
+
+/**
+ * Unit test for {@link CarTrustAgentEnrollmentService} and {@link CarTrustedDeviceService}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarTrustAgentEnrollmentServiceTest {
+
+ private static final int TEST_HANDLE1 = 1;
+ private static final int TEST_HANDLE2 = 2;
+ private static final String TEST_TOKEN = "test_escrow_token";
+ private static final String ADDRESS = "00:11:22:33:AA:BB";
+ private static final String DEFAULT_NAME = "My Device";
+ private static final TrustedDeviceInfo DEVICE_INFO_FOR_HANDLE1 = new TrustedDeviceInfo(
+ TEST_HANDLE1, ADDRESS, DEFAULT_NAME);
+ private static final TrustedDeviceInfo DEVICE_INFO_FOR_HANDLE2 = new TrustedDeviceInfo(
+ TEST_HANDLE2, ADDRESS, DEFAULT_NAME);
+
+ private Context mContext;
+ private CarTrustedDeviceService mCarTrustedDeviceService;
+ private CarTrustAgentEnrollmentService mCarTrustAgentEnrollmentService;
+ private BluetoothDevice mBluetoothDevice;
+ private int mUserId;
+ @Mock
+ private CarTrustAgentBleManager mMockCarTrustAgentBleManager;
+
+ private CarTrustAgentEnrollmentService.CarTrustAgentEnrollmentRequestDelegate mEnrollDelegate =
+ new CarTrustAgentEnrollmentService.CarTrustAgentEnrollmentRequestDelegate() {
+ @Override
+ public void addEscrowToken(byte[] token, int uid) {
+ }
+
+ @Override
+ public void removeEscrowToken(long handle, int uid) {
+ }
+
+ @Override
+ public void isEscrowTokenActive(long handle, int uid) {
+ }
+ };
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+
+ mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(ADDRESS);
+ mContext = InstrumentationRegistry.getTargetContext();
+ mCarTrustedDeviceService = new CarTrustedDeviceService(mContext);
+ mCarTrustAgentEnrollmentService = new CarTrustAgentEnrollmentService(mContext,
+ mCarTrustedDeviceService, mMockCarTrustAgentBleManager);
+ mCarTrustedDeviceService.init();
+ mCarTrustAgentEnrollmentService.init();
+ mCarTrustAgentEnrollmentService.setEnrollmentRequestDelegate(mEnrollDelegate);
+ mUserId = new CarUserManagerHelper(mContext).getCurrentProcessUserId();
+ mCarTrustAgentEnrollmentService.onRemoteDeviceConnected(mBluetoothDevice);
+ }
+
+ @After
+ public void tearDown() {
+ // Need to clear the shared preference
+ mCarTrustAgentEnrollmentService.onEscrowTokenRemoved(TEST_HANDLE1, mUserId);
+ mCarTrustAgentEnrollmentService.onEscrowTokenRemoved(TEST_HANDLE2, mUserId);
+
+ }
+
+ @Test
+ public void testDisableEnrollment_startEnrollmentAdvertisingFail() {
+ mCarTrustAgentEnrollmentService.setTrustedDeviceEnrollmentEnabled(false);
+ mCarTrustAgentEnrollmentService.startEnrollmentAdvertising();
+ verify(mMockCarTrustAgentBleManager, never()).startEnrollmentAdvertising();
+ }
+
+ @Test
+ public void testEncryptionHandshake() {
+ mCarTrustAgentEnrollmentService.setEncryptionRunner(
+ EncryptionRunnerFactory.newDummyRunner());
+ assertThat(mCarTrustAgentEnrollmentService.mEnrollmentState).isEqualTo(
+ mCarTrustAgentEnrollmentService.ENROLLMENT_STATE_NONE);
+ // Have received device unique id.
+ UUID uuid = UUID.randomUUID();
+ mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(Utils.uuidToBytes(uuid));
+ assertThat(mCarTrustAgentEnrollmentService.mEnrollmentState).isEqualTo(
+ mCarTrustAgentEnrollmentService.ENROLLMENT_STATE_UNIQUE_ID);
+ assertThat(mCarTrustAgentEnrollmentService.mEncryptionState).isEqualTo(
+ HandshakeMessage.HandshakeState.UNKNOWN);
+ // send device unique id
+ verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice),
+ eq(Utils.uuidToBytes(mCarTrustedDeviceService.getUniqueId())), any(), eq(false));
+
+ // Have received handshake request.
+ mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(
+ DummyEncryptionRunner.INIT.getBytes());
+ assertThat(mCarTrustAgentEnrollmentService.mEncryptionState).isEqualTo(
+ HandshakeMessage.HandshakeState.IN_PROGRESS);
+ // Send response to init handshake request
+ verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice),
+ eq(DummyEncryptionRunner.INIT_RESPONSE.getBytes()), any(), eq(false));
+
+ mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(
+ DummyEncryptionRunner.CLIENT_RESPONSE.getBytes());
+ assertThat(mCarTrustAgentEnrollmentService.mEncryptionState).isEqualTo(
+ HandshakeMessage.HandshakeState.VERIFICATION_NEEDED);
+ verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice),
+ eq(DummyEncryptionRunner.INIT_RESPONSE.getBytes()), any(), eq(false));
+
+ // Completed the handshake by confirming the verification code.
+ mCarTrustAgentEnrollmentService.enrollmentHandshakeAccepted(mBluetoothDevice);
+ verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice),
+ eq(mCarTrustAgentEnrollmentService.CONFIRMATION_SIGNAL), any(), eq(false));
+ assertThat(mCarTrustAgentEnrollmentService.mEncryptionState).isEqualTo(
+ HandshakeMessage.HandshakeState.FINISHED);
+ assertThat(mCarTrustAgentEnrollmentService.mEnrollmentState).isEqualTo(
+ mCarTrustAgentEnrollmentService.ENROLLMENT_STATE_ENCRYPTION_COMPLETED);
+ }
+
+ @Test
+ public void testOnEscrowTokenAdded_tokenRequiresActivation() {
+ mCarTrustAgentEnrollmentService.onEscrowTokenAdded(TEST_TOKEN.getBytes(), TEST_HANDLE1,
+ mUserId);
+
+ // Token has not been activated, the number of enrolled trusted device will remain the same.
+ assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
+ mUserId)).isEmpty();
+ assertThat(mCarTrustAgentEnrollmentService.isEscrowTokenActive(TEST_HANDLE1,
+ mUserId)).isFalse();
+ }
+
+ @Test
+ public void testOnEscrowTokenActiveStateChange_true_addTrustedDevice() {
+ // Set up the service to go through the handshake
+ setupEncryptionHandshake();
+
+ // Token has been activated and added to the shared preference
+ mCarTrustAgentEnrollmentService.onEscrowTokenActiveStateChanged(
+ TEST_HANDLE1, /* isTokenActive= */ true, mUserId);
+
+ verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice), any(),
+ any(), eq(true));
+ assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
+ mUserId)).containsExactly(DEVICE_INFO_FOR_HANDLE1);
+ assertThat(mCarTrustAgentEnrollmentService.isEscrowTokenActive(TEST_HANDLE1,
+ mUserId)).isTrue();
+ }
+
+ @Test
+ public void testOnEscrowTokenActiveStateChange_false_doNotAddTrustedDevice() {
+ // Set up the service to go through the handshake
+ setupEncryptionHandshake();
+
+ // Token activation fail
+ mCarTrustAgentEnrollmentService.onEscrowTokenActiveStateChanged(
+ TEST_HANDLE1, /* isTokenActive= */ false, mUserId);
+
+ assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
+ mUserId)).isEmpty();
+ }
+
+ @Test
+ public void testOnEscrowTokenRemoved_removeOneTrustedDevice() {
+ setupEncryptionHandshake();
+ mCarTrustAgentEnrollmentService.onEscrowTokenActiveStateChanged(
+ TEST_HANDLE1, /* isTokenActive= */ true,
+ mUserId);
+ mCarTrustAgentEnrollmentService.onEscrowTokenActiveStateChanged(
+ TEST_HANDLE2, /* isTokenActive= */ true,
+ mUserId);
+
+ assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
+ mUserId)).containsExactly(DEVICE_INFO_FOR_HANDLE1, DEVICE_INFO_FOR_HANDLE2);
+ assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(
+ mUserId);
+ assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE2)).isEqualTo(
+ mUserId);
+
+ // Remove all handles
+ mCarTrustAgentEnrollmentService.onEscrowTokenRemoved(TEST_HANDLE1, mUserId);
+
+ assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
+ mUserId)).containsExactly(DEVICE_INFO_FOR_HANDLE2);
+ assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(-1);
+ assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE2)).isEqualTo(
+ mUserId);
+ }
+
+ @Test
+ public void testGetUserHandleByTokenHandle_nonExistentHandle() {
+ assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(-1);
+ }
+
+ @Test
+ public void testGetUserHandleByTokenHandle_existingHandle() {
+ setupEncryptionHandshake();
+ mCarTrustAgentEnrollmentService.onEscrowTokenActiveStateChanged(
+ TEST_HANDLE1, /* isTokenActive= */ true, mUserId);
+ assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(
+ mUserId);
+ }
+
+ private void setupEncryptionHandshake() {
+ mCarTrustAgentEnrollmentService.setEncryptionRunner(
+ EncryptionRunnerFactory.newDummyRunner());
+ UUID uuid = UUID.randomUUID();
+ mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(Utils.uuidToBytes(uuid));
+ mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(
+ DummyEncryptionRunner.INIT.getBytes());
+ mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(
+ DummyEncryptionRunner.CLIENT_RESPONSE.getBytes());
+ mCarTrustAgentEnrollmentService.enrollmentHandshakeAccepted(mBluetoothDevice);
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java b/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
index 6519f0c..772abc7 100644
--- a/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
@@ -60,6 +60,8 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.function.Consumer;
+
@SmallTest
public class VmsClientManagerTest {
private static final String HAL_CLIENT_NAME = "VmsHalClient";
@@ -84,7 +86,8 @@
@Mock
private VmsHalService mHal;
- private IBinder mHalClient;
+ private Consumer<IBinder> mHalClientConnected;
+ private Runnable mHalClientDisconnected;
@Mock
private VmsClientManager.ConnectionListener mConnectionListener;
@@ -115,13 +118,18 @@
mUserId = 10;
when(mUserManager.getCurrentForegroundUserId()).thenAnswer((invocation) -> mUserId);
- mHalClient = new Binder();
- when(mHal.getPublisherClient()).thenReturn(mHalClient);
-
mClientManager = new VmsClientManager(mContext, mUserService, mUserManager, mHal);
mClientManager.registerConnectionListener(mConnectionListener);
- verify(mConnectionListener).onClientConnected(HAL_CLIENT_NAME, mHalClient);
- reset(mConnectionListener);
+
+ @SuppressWarnings("unchecked")
+ ArgumentCaptor<Consumer<IBinder>> onClientConnectedCaptor =
+ ArgumentCaptor.forClass(Consumer.class);
+ ArgumentCaptor<Runnable> onClientDisconnectedCaptor =
+ ArgumentCaptor.forClass(Runnable.class);
+ verify(mHal).setPublisherConnectionCallbacks(
+ onClientConnectedCaptor.capture(), onClientDisconnectedCaptor.capture());
+ mHalClientConnected = onClientConnectedCaptor.getValue();
+ mHalClientDisconnected = onClientDisconnectedCaptor.getValue();
}
@After
@@ -130,6 +138,7 @@
verify(mContext, atLeast(0)).getResources();
verify(mContext, atLeast(0)).getPackageManager();
verifyNoMoreInteractions(mContext);
+ verifyNoMoreInteractions(mHal);
}
@Test
@@ -162,18 +171,28 @@
VmsClientManager.ConnectionListener listener =
Mockito.mock(VmsClientManager.ConnectionListener.class);
mClientManager.registerConnectionListener(listener);
- verify(listener).onClientConnected(HAL_CLIENT_NAME, mHalClient);
+ }
+
+ @Test
+ public void testRegisterConnectionListener_AfterHalClientConnected() {
+ IBinder halClient = bindHalClient();
+
+ VmsClientManager.ConnectionListener listener =
+ Mockito.mock(VmsClientManager.ConnectionListener.class);
+ mClientManager.registerConnectionListener(listener);
+ verify(listener).onClientConnected(HAL_CLIENT_NAME, halClient);
}
@Test
public void testRegisterConnectionListener_AfterClientsConnected() {
+ IBinder halClient = bindHalClient();
IBinder systemBinder = bindSystemClient();
IBinder userBinder = bindUserClient();
VmsClientManager.ConnectionListener listener =
Mockito.mock(VmsClientManager.ConnectionListener.class);
mClientManager.registerConnectionListener(listener);
- verify(listener).onClientConnected(HAL_CLIENT_NAME, mHalClient);
+ verify(listener).onClientConnected(HAL_CLIENT_NAME, halClient);
verify(listener).onClientConnected(eq(SYSTEM_CLIENT_NAME), eq(systemBinder));
verify(listener).onClientConnected(eq(USER_CLIENT_NAME), eq(userBinder));
}
@@ -334,6 +353,18 @@
}
@Test
+ public void testHalClientConnected() {
+ IBinder binder = bindHalClient();
+ verify(mConnectionListener).onClientConnected(eq(HAL_CLIENT_NAME), eq(binder));
+ }
+
+ private IBinder bindHalClient() {
+ IBinder binder = new Binder();
+ mHalClientConnected.accept(binder);
+ return binder;
+ }
+
+ @Test
public void testOnSystemServiceConnected() {
IBinder binder = bindSystemClient();
verify(mConnectionListener).onClientConnected(eq(SYSTEM_CLIENT_NAME), eq(binder));
@@ -368,6 +399,14 @@
}
@Test
+ public void testOnHalClientDisconnected() throws Exception {
+ bindHalClient();
+ mHalClientDisconnected.run();
+
+ verify(mConnectionListener).onClientDisconnected(eq(HAL_CLIENT_NAME));
+ }
+
+ @Test
public void testOnSystemServiceDisconnected() throws Exception {
notifySystemUserUnlocked();
verifySystemBind(1);
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 a46cf37..0745945 100644
--- a/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
+++ b/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
@@ -60,7 +60,7 @@
*
* @hide
*/
-public class CarUserManagerHelper {
+public final class CarUserManagerHelper {
private static final String TAG = "CarUserManagerHelper";
private static final int BOOT_USER_NOT_FOUND = -1;