diff --git a/automotive/automotive-lib/.gitignore b/automotive/automotive-lib/.gitignore
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/automotive/automotive-lib/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/automotive/automotive-lib/build.gradle b/automotive/automotive-lib/build.gradle
new file mode 100644
index 000000000..4fc7ecc79
--- /dev/null
+++ b/automotive/automotive-lib/build.gradle
@@ -0,0 +1,41 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.2"
+
+
+ defaultConfig {
+ minSdkVersion 24
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles 'consumer-rules.pro'
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
+
+ implementation "androidx.constraintlayout:constraintlayout:$constraint_layout_version"
+ implementation "androidx.preference:preference:$androidx_preference_version"
+ implementation "com.google.android.material:material:$material_version"
+
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.core:core-ktx:1.1.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+}
diff --git a/automotive/automotive-lib/consumer-rules.pro b/automotive/automotive-lib/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/automotive/automotive-lib/proguard-rules.pro b/automotive/automotive-lib/proguard-rules.pro
new file mode 100644
index 000000000..f1b424510
--- /dev/null
+++ b/automotive/automotive-lib/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/automotive/automotive-lib/src/androidTest/java/com/example/android/uamp/automotive/lib/ExampleInstrumentedTest.kt b/automotive/automotive-lib/src/androidTest/java/com/example/android/uamp/automotive/lib/ExampleInstrumentedTest.kt
new file mode 100644
index 000000000..2b6222cb5
--- /dev/null
+++ b/automotive/automotive-lib/src/androidTest/java/com/example/android/uamp/automotive/lib/ExampleInstrumentedTest.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.uamp.automotive.lib
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.assertEquals
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.example.android.uamp.automotive.lib.test", appContext.packageName)
+ }
+}
diff --git a/automotive/automotive-lib/src/main/AndroidManifest.xml b/automotive/automotive-lib/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..c6e56648a
--- /dev/null
+++ b/automotive/automotive-lib/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/ListPreference.kt b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/ListPreference.kt
new file mode 100644
index 000000000..cffcede43
--- /dev/null
+++ b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/ListPreference.kt
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.uamp.automotive.lib
+
+import android.content.Context
+import android.content.res.TypedArray
+import android.os.Parcel
+import android.os.Parcelable
+import android.text.TextUtils
+import android.util.AttributeSet
+import android.util.Log
+import androidx.annotation.ArrayRes
+import androidx.core.content.res.TypedArrayUtils
+import androidx.preference.Preference
+
+const val LIST_PREFERENCE_ARG_KEY = "AutomotiveListPreferenceKey"
+
+/**
+ * A {@link Preference} that displays a list of entries in a {@link ListPreferenceFragment}.
+ *
+ * This class is taken largely as is from {@link androidx.preference.ListPreference} other than
+ * the modification to display entries in a full-screen fragment rather than a dialog.
+ *
+ *
This preference saves a string value. This string will be the value from the
+ * {@link #setEntryValues(CharSequence[])} array.
+ *
+ * @attr name android:entries
+ * @attr name android:entryValues
+ */
+class ListPreference : Preference {
+
+ private val TAG = "ListPreference"
+ private var entries: Array? = null
+ private var entryValues: Array? = null
+ private var value: String? = null
+ private var summary: String? = null
+ private var valueSet: Boolean = false
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int)
+ : super(context, attrs, defStyleAttr, defStyleRes) {
+ init(context, attrs, defStyleAttr, defStyleRes)
+ }
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int)
+ : this(context, attrs, defStyleAttr, R.style.AutomotivePreference_Preference)
+
+ constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, R.attr.preferenceStyle)
+
+ constructor(context: Context) : this(context, null)
+
+ private fun init(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) {
+
+ val attributes = context.obtainStyledAttributes(
+ attrs, R.styleable.ListPreference, defStyleAttr, defStyleRes)
+
+ entries = TypedArrayUtils.getTextArray(attributes, R.styleable.ListPreference_entries,
+ R.styleable.ListPreference_android_entries)
+
+ entryValues = TypedArrayUtils.getTextArray(attributes, R.styleable.ListPreference_entryValues,
+ R.styleable.ListPreference_android_entryValues)
+
+ attributes.recycle()
+
+ extras.putString(LIST_PREFERENCE_ARG_KEY, key)
+ fragment = ListPreferenceFragment::class.qualifiedName
+ }
+
+ /**
+ * Sets the human-readable entries to be shown in the list. This will be shown in subsequent
+ * dialogs.
+ *
+ *
+ * Each entry must have a corresponding index in [.setEntryValues].
+ *
+ * @param entries The entries
+ * @see .setEntryValues
+ */
+ fun setEntries(entries: Array) {
+ this.entries = entries
+ }
+
+ /**
+ * @param entriesResId The entries array as a resource
+ * @see .setEntries
+ */
+ fun setEntries(@ArrayRes entriesResId: Int) {
+ setEntries(context.resources.getTextArray(entriesResId))
+ }
+
+ /**
+ * The list of entries to be shown in the list in subsequent dialogs.
+ *
+ * @return The list as an array
+ */
+ fun getEntries(): Array? {
+ return entries
+ }
+
+ /**
+ * The array to find the value to save for a preference when an entry from entries is
+ * selected. If a user clicks on the second item in entries, the second item in this array
+ * will be saved to the preference.
+ *
+ * @param entryValues The array to be used as values to save for the preference
+ */
+ fun setEntryValues(entryValues: Array) {
+ this.entryValues = entryValues
+ }
+
+ /**
+ * @param entryValuesResId The entry values array as a resource
+ * @see .setEntryValues
+ */
+ fun setEntryValues(@ArrayRes entryValuesResId: Int) {
+ setEntryValues(context.resources.getTextArray(entryValuesResId))
+ }
+
+ /**
+ * Returns the array of values to be saved for the preference.
+ *
+ * @return The array of values
+ */
+ fun getEntryValues(): Array? {
+ return entryValues
+ }
+
+ override fun setSummary(summary: CharSequence?) {
+ super.setSummary(summary)
+ if (summary == null && this.summary != null) {
+ this.summary = null
+ } else if (summary != null && summary != this.summary) {
+ this.summary = summary.toString()
+ }
+ }
+
+ override fun getSummary(): CharSequence {
+ if (summaryProvider != null) {
+ return summaryProvider!!.provideSummary(this)
+ }
+ val entry = getEntry()
+ val summary = super.getSummary()
+ if (this.summary == null) {
+ return summary
+ }
+ val formattedString = String.format(this.summary!!, entry ?: "")
+ if (TextUtils.equals(formattedString, summary)) {
+ return summary
+ }
+ Log.w(TAG,
+ "Setting a summary with a String formatting marker is no longer supported." +
+ " You should use a SummaryProvider instead.")
+ return formattedString
+ }
+
+ /**
+ * Sets the value of the key. This should be one of the entries in [.getEntryValues].
+ *
+ * @param value The value to set for the key
+ */
+ fun setValue(value: String?) {
+ // Always persist/notify the first time.
+ val changed = !TextUtils.equals(this.value, value)
+ if (changed || !valueSet) {
+ this.value = value
+ valueSet = true
+ persistString(value)
+ if (changed) {
+ notifyChanged()
+ }
+ }
+ }
+
+ /**
+ * Returns the value of the key. This should be one of the entries in [.getEntryValues].
+ *
+ * @return The value of the key
+ */
+ fun getValue(): String? {
+ return value
+ }
+
+ /**
+ * Returns the entry corresponding to the current value.
+ *
+ * @return The entry corresponding to the current value, or `null`
+ */
+ fun getEntry(): CharSequence? {
+ val index = getValueIndex()
+ return if (index >= 0 && entries != null) entries!![index] else null
+ }
+
+ /**
+ * Returns the index of the given value (in the entry values array).
+ *
+ * @param value The value whose index should be returned
+ * @return The index of the value, or -1 if not found
+ */
+ fun findIndexOfValue(value: String?): Int {
+ if (value != null && entryValues != null) {
+ for (i in entryValues!!.indices.reversed()) {
+ if (entryValues!![i] == value) {
+ return i
+ }
+ }
+ }
+ return -1
+ }
+
+ /**
+ * Sets the value to the given index from the entry values.
+ *
+ * @param index The index of the value to set
+ */
+ fun setValueIndex(index: Int) {
+ if (entryValues != null) {
+ setValue(entryValues!![index].toString())
+ }
+ }
+
+ private fun getValueIndex(): Int {
+ return findIndexOfValue(value)
+ }
+
+ protected override fun onGetDefaultValue(a: TypedArray, index: Int): Any? {
+ return a.getString(index)
+ }
+
+ override fun onSetInitialValue(defaultValue: Any?) {
+ setValue(getPersistedString(defaultValue as String?))
+ }
+
+ override fun onSaveInstanceState(): Parcelable {
+ val superState = super.onSaveInstanceState()
+ if (isPersistent) {
+ // No need to save instance state since it's persistent
+ return superState
+ }
+
+ val myState = SavedState(superState)
+ myState.mValue = getValue()
+ return myState
+ }
+
+ override fun onRestoreInstanceState(state: Parcelable?) {
+ if (state == null || state.javaClass != SavedState::class.java) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state)
+ return
+ }
+
+ val myState = state as SavedState?
+ super.onRestoreInstanceState(myState!!.superState)
+ setValue(myState.mValue)
+ }
+
+ private class SavedState : BaseSavedState {
+
+ internal var mValue: String? = null
+
+ internal constructor(source: Parcel) : super(source) {
+ mValue = source.readString()
+ }
+
+ internal constructor(superState: Parcelable) : super(superState)
+
+ override fun writeToParcel(dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ dest.writeString(mValue)
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ companion object CREATOR : Parcelable.Creator {
+ override fun createFromParcel(parcel: Parcel): SavedState {
+ return SavedState(parcel)
+ }
+
+ override fun newArray(size: Int): Array {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+
+ /**
+ * A simple [androidx.preference.Preference.SummaryProvider] implementation for a
+ * [ListPreference]. If no value has been set, the summary displayed will be 'Not set',
+ * otherwise the summary displayed will be the entry set for this preference.
+ */
+ class SimpleSummaryProvider : SummaryProvider {
+ companion object {
+ val instance = SimpleSummaryProvider()
+ }
+
+ override fun provideSummary(preference: ListPreference): CharSequence? {
+ return if (TextUtils.isEmpty(preference.getEntry())) {
+ preference.context.getString(R.string.not_set)
+ } else {
+ preference.getEntry()
+ }
+ }
+
+ }
+}
diff --git a/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/ListPreferenceAdapter.kt b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/ListPreferenceAdapter.kt
new file mode 100644
index 000000000..b489548e2
--- /dev/null
+++ b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/ListPreferenceAdapter.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.uamp.automotive.lib
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.RadioButton
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+
+/**
+ * Adapter that provides bindings between a {@link ListPreference} and set of views to display and
+ * allow for selection of the entries of the preference.
+ */
+internal class ListPreferenceAdapter(preference: ListPreference) :
+ RecyclerView.Adapter() {
+
+ private var entries: Array? = preference.getEntries()
+ private var selectedEntry: Int = preference.findIndexOfValue(preference.getValue())
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ return ViewHolder(LayoutInflater.from(parent.context)
+ .inflate(R.layout.radio_button_list_item, parent, false))
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ holder.title.text = entries?.get(position)
+ holder.radioButton.isChecked = position == selectedEntry
+ holder.holderView.setOnClickListener {
+ val previousIndex = selectedEntry
+ selectedEntry = position
+ notifyItemChanged(previousIndex)
+ notifyItemChanged(position)
+ }
+ }
+
+ fun getSelectedEntry(): Int {
+ return selectedEntry
+ }
+
+ override fun getItemCount(): Int {
+ entries?.let { return entries!!.size }
+ return 0
+ }
+
+ class ViewHolder(val holderView: View) : RecyclerView.ViewHolder(holderView) {
+ val title: TextView = holderView.findViewById(R.id.title)
+ val radioButton: RadioButton = holderView.findViewById(R.id.radio_button_widget)
+ }
+}
\ No newline at end of file
diff --git a/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/ListPreferenceFragment.kt b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/ListPreferenceFragment.kt
new file mode 100644
index 000000000..d33959f26
--- /dev/null
+++ b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/ListPreferenceFragment.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.uamp.automotive.lib
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.preference.PreferenceFragmentCompat
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+
+/**
+ * Fragment that is used to display the multi-selection entries of a
+ * {@link MultiSelectListPreference}.
+ */
+class ListPreferenceFragment : Fragment() {
+
+ private lateinit var preference: ListPreference
+ private lateinit var adapter: ListPreferenceAdapter
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.list_preference, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val recyclerView = view.findViewById(R.id.list)
+ preference = getPreference()
+ adapter = ListPreferenceAdapter(preference)
+ recyclerView.adapter = adapter
+ recyclerView.layoutManager = LinearLayoutManager(context)
+ }
+
+ private fun getPreference() : ListPreference {
+ val key = arguments?.getCharSequence(LIST_PREFERENCE_ARG_KEY)
+ ?: throw IllegalStateException("Preference arguments cannot be null")
+ return (targetFragment as PreferenceFragmentCompat).findPreference(key)
+ ?: throw IllegalStateException("Unable to find ListPreference with key: $key")
+ }
+
+ override fun onPause() {
+ super.onPause()
+ val selectedIndex = adapter.getSelectedEntry()
+ if (selectedIndex < 0) {
+ return
+ }
+
+ val entryValue = preference.getEntryValues()!![selectedIndex].toString()
+ if (preference.callChangeListener(entryValue)) {
+ preference.setValue(entryValue)
+ }
+ }
+}
\ No newline at end of file
diff --git a/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/MultiSelectListPreference.kt b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/MultiSelectListPreference.kt
new file mode 100644
index 000000000..6511e19fa
--- /dev/null
+++ b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/MultiSelectListPreference.kt
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.uamp.automotive.lib
+
+import android.content.Context
+import android.content.res.TypedArray
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.AttributeSet
+import androidx.annotation.ArrayRes
+import androidx.core.content.res.TypedArrayUtils
+import androidx.preference.Preference
+import java.util.Collections
+import kotlin.collections.HashSet
+
+const val MULTI_SELECT_LIST_PREFERENCE_ARG_KEY = "AutomotiveMultiSelectListPreferenceKey"
+
+/**
+ * A {@link Preference} that displays a list of entries in a {@link ListPreferenceFragment}.
+ *
+ * This class is taken largely as is from {@link androidx.preference.ListPreference} other than
+ * the modification to display entries in a full-screen fragment rather than a dialog.
+ *
+ * This preference saves a string value. This string will be the value from the
+ * {@link #setEntryValues(CharSequence[])} array.
+ *
+ * @attr name android:entries
+ * @attr name android:entryValues
+ */
+class MultiSelectListPreference : Preference {
+
+ private var entries: Array? = null
+ private var entryValues: Array? = null
+ private val values = HashSet()
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int)
+ : super(context, attrs, defStyleAttr, defStyleRes) {
+ init(context, attrs, defStyleAttr, defStyleRes)
+ }
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int)
+ : this(context, attrs, defStyleAttr, R.style.AutomotivePreference_Preference)
+
+ constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, R.attr.preferenceStyle)
+
+ constructor(context: Context) : this(context, null)
+
+
+ private fun init(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) {
+
+ val attributes = context.obtainStyledAttributes(
+ attrs, R.styleable.ListPreference, defStyleAttr, defStyleRes)
+
+ entries = TypedArrayUtils.getTextArray(attributes, R.styleable.ListPreference_entries,
+ R.styleable.ListPreference_android_entries)
+
+ entryValues = TypedArrayUtils.getTextArray(attributes, R.styleable.ListPreference_entryValues,
+ R.styleable.ListPreference_android_entryValues)
+
+ attributes.recycle()
+
+ extras.putString(MULTI_SELECT_LIST_PREFERENCE_ARG_KEY, key)
+ fragment = MultiSelectListPreferenceFragment::class.qualifiedName
+ }
+
+ /**
+ * Sets the human-readable entries to be shown in the list. This will be shown in subsequent
+ * dialogs.
+ *
+ *
+ * Each entry must have a corresponding index in [.setEntryValues].
+ *
+ * @param entries The entries
+ * @see .setEntryValues
+ */
+ fun setEntries(entries: Array) {
+ this.entries = entries
+ }
+
+ /**
+ * @param entriesResId The entries array as a resource
+ * @see .setEntries
+ */
+ fun setEntries(@ArrayRes entriesResId: Int) {
+ setEntries(context.resources.getTextArray(entriesResId))
+ }
+
+ /**
+ * The list of entries to be shown in the list in subsequent dialogs.
+ *
+ * @return The list as an array
+ */
+ fun getEntries(): Array? {
+ return entries
+ }
+
+ /**
+ * The array to find the value to save for a preference when an entry from entries is selected. If
+ * a user clicks on the second item in entries, the second item in this array will be saved to the
+ * preference.
+ *
+ * @param entryValues The array to be used as values to save for the preference
+ */
+ fun setEntryValues(entryValues: Array) {
+ this.entryValues = entryValues
+ }
+
+ /**
+ * @param entryValuesResId The entry values array as a resource
+ * @see .setEntryValues
+ */
+ fun setEntryValues(@ArrayRes entryValuesResId: Int) {
+ setEntryValues(context.resources.getTextArray(entryValuesResId))
+ }
+
+ /**
+ * Returns the array of values to be saved for the preference.
+ *
+ * @return The array of values
+ */
+ fun getEntryValues(): Array? {
+ return entryValues
+ }
+
+ /**
+ * Sets the values for the key. This should contain entries in [.getEntryValues].
+ *
+ * @param values The values to set for the key
+ */
+ fun setValues(values: Set) {
+ this.values.clear()
+ this.values.addAll(values)
+
+ persistStringSet(values)
+ notifyChanged()
+ }
+
+ /**
+ * Retrieves the current values of the key.
+ *
+ * @return The set of current values
+ */
+ fun getValues(): Set {
+ return values
+ }
+
+ /**
+ * Returns the index of the given value (in the entry values array).
+ *
+ * @param value The value whose index should be returned
+ * @return The index of the value, or -1 if not found
+ */
+ fun findIndexOfValue(value: String?): Int {
+ if (value != null && entryValues != null) {
+ for (i in entryValues!!.indices.reversed()) {
+ if (entryValues!![i] == value) {
+ return i
+ }
+ }
+ }
+ return -1
+ }
+
+ protected fun getSelectedItems(): BooleanArray {
+ val entries = entryValues
+ val entryCount = entries!!.size
+ val values = this.values
+ val result = BooleanArray(entryCount)
+
+ for (i in 0 until entryCount) {
+ result[i] = values.contains(entries[i].toString())
+ }
+
+ return result
+ }
+
+ override fun onGetDefaultValue(a: TypedArray, index: Int): Any {
+ val defaultValues = a.getTextArray(index)
+ val result = HashSet()
+
+ for (defaultValue in defaultValues) {
+ result.add(defaultValue.toString())
+ }
+
+ return result
+ }
+
+ override fun onSetInitialValue(defaultValue: Any?) {
+ setValues(getPersistedStringSet(defaultValue as Set?))
+ }
+
+ override fun onSaveInstanceState(): Parcelable {
+ val superState = super.onSaveInstanceState()
+ if (isPersistent()) {
+ // No need to save instance state
+ return superState
+ }
+
+ val myState = SavedState(superState)
+ myState.mValues = getValues()
+ return myState
+ }
+
+ override fun onRestoreInstanceState(state: Parcelable?) {
+ if (state == null || state.javaClass != SavedState::class.java) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state)
+ return
+ }
+
+ val myState = state as SavedState?
+ super.onRestoreInstanceState(myState!!.superState)
+ setValues(myState.mValues)
+ }
+
+ private class SavedState : BaseSavedState {
+
+ internal lateinit var mValues: Set
+
+ internal constructor(source: Parcel) : super(source) {
+ val size = source.readInt()
+ mValues = HashSet()
+ val strings = arrayOfNulls(size)
+ source.readStringArray(strings)
+
+ Collections.addAll(mValues as HashSet, *strings)
+ }
+
+ internal constructor(superState: Parcelable) : super(superState)
+
+ override fun writeToParcel(dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ dest.writeInt(mValues.size)
+ dest.writeStringArray(mValues.toTypedArray())
+ }
+
+ companion object CREATOR : Parcelable.Creator {
+ override fun createFromParcel(parcel: Parcel): SavedState {
+ return SavedState(parcel)
+ }
+
+ override fun newArray(size: Int): Array {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/MultiSelectListPreferenceAdapter.kt b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/MultiSelectListPreferenceAdapter.kt
new file mode 100644
index 000000000..69b779b79
--- /dev/null
+++ b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/MultiSelectListPreferenceAdapter.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.uamp.automotive.lib
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CheckBox
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import java.util.HashSet
+
+/**
+ * Adapter that provides bindings between a {@link ListPreference} and set of views to display and
+ * allow for selection of the entries of the preference.
+ */
+class MultiSelectListPreferenceAdapter(preference: MultiSelectListPreference) :
+ RecyclerView.Adapter() {
+
+ private var selectedEntries: MutableSet = HashSet(preference.getValues())
+ private var entries: Array? = preference.getEntries()
+ private var entryValues: Array? = preference.getEntryValues()
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ return ViewHolder(LayoutInflater.from(parent.context)
+ .inflate(R.layout.check_box_list_item, parent, false))
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ holder.title.text = entries?.get(position)
+ val entryValue = entryValues?.get(position).toString()
+
+ holder.checkBox.isChecked = selectedEntries.contains(entryValue)
+ holder.holderView.setOnClickListener {
+ if (selectedEntries.contains(entryValue)) {
+ selectedEntries.remove(entryValue)
+ } else {
+ selectedEntries.add(entryValue)
+ }
+
+ notifyItemChanged(position)
+ }
+ }
+
+ fun getSelectedEntries(): Set {
+ return selectedEntries
+ }
+
+ override fun getItemCount(): Int {
+ entries?.let { return entries!!.size }
+ return 0
+ }
+
+ class ViewHolder(val holderView: View) : RecyclerView.ViewHolder(holderView) {
+ val title: TextView = itemView.findViewById(R.id.title)
+ val checkBox: CheckBox = itemView.findViewById(R.id.check_box_widget)
+ }
+}
\ No newline at end of file
diff --git a/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/MultiSelectListPreferenceFragment.kt b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/MultiSelectListPreferenceFragment.kt
new file mode 100644
index 000000000..f6f610ba0
--- /dev/null
+++ b/automotive/automotive-lib/src/main/java/com/example/android/uamp/automotive/lib/MultiSelectListPreferenceFragment.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.uamp.automotive.lib
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.preference.PreferenceFragmentCompat
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+
+/**
+ * Fragment that is used to display the multi-selection entries of a
+ * {@link MultiSelectListPreference}.
+ */
+class MultiSelectListPreferenceFragment : Fragment() {
+
+ private lateinit var preference: MultiSelectListPreference
+ private lateinit var adapter: MultiSelectListPreferenceAdapter
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.list_preference, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val recyclerView = view.findViewById(R.id.list)
+ preference = getPreference()
+ adapter = MultiSelectListPreferenceAdapter(preference)
+ recyclerView.adapter = adapter
+ recyclerView.layoutManager = LinearLayoutManager(context)
+ }
+
+ private fun getPreference() : MultiSelectListPreference {
+ val key = arguments?.getCharSequence(MULTI_SELECT_LIST_PREFERENCE_ARG_KEY)
+ ?: throw IllegalStateException("Preference arguments cannot be null")
+ return (targetFragment as PreferenceFragmentCompat).findPreference(key)
+ ?: throw IllegalStateException("Unable to find ListPreference with key: $key")
+ }
+
+ override fun onPause() {
+ super.onPause()
+
+ val newValues = adapter.getSelectedEntries()
+ if (preference.callChangeListener(newValues)) {
+ preference.setValues(newValues)
+ }
+ }
+}
\ No newline at end of file
diff --git a/automotive/src/main/res/layout/preference.xml b/automotive/automotive-lib/src/main/res/color/primary_text.xml
similarity index 50%
rename from automotive/src/main/res/layout/preference.xml
rename to automotive/automotive-lib/src/main/res/color/primary_text.xml
index 0f30573ba..380207b91 100644
--- a/automotive/src/main/res/layout/preference.xml
+++ b/automotive/automotive-lib/src/main/res/color/primary_text.xml
@@ -1,6 +1,6 @@
-
-
-
-
-
\ No newline at end of file
+ -->
+
+
+
+
diff --git a/automotive/automotive-lib/src/main/res/color/secondary_text.xml b/automotive/automotive-lib/src/main/res/color/secondary_text.xml
new file mode 100644
index 000000000..f972bf044
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/color/secondary_text.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/automotive/src/main/res/drawable/sign_in_toolbar_back_icon.xml b/automotive/automotive-lib/src/main/res/drawable/toolbar_back_icon.xml
similarity index 79%
rename from automotive/src/main/res/drawable/sign_in_toolbar_back_icon.xml
rename to automotive/automotive-lib/src/main/res/drawable/toolbar_back_icon.xml
index b84f43548..3db8cded3 100644
--- a/automotive/src/main/res/drawable/sign_in_toolbar_back_icon.xml
+++ b/automotive/automotive-lib/src/main/res/drawable/toolbar_back_icon.xml
@@ -1,12 +1,12 @@
@@ -25,4 +25,4 @@
-
+
\ No newline at end of file
diff --git a/automotive/src/main/res/drawable/sign_in_toolbar_back_ripple_background.xml b/automotive/automotive-lib/src/main/res/drawable/toolbar_back_ripple_background.xml
similarity index 80%
rename from automotive/src/main/res/drawable/sign_in_toolbar_back_ripple_background.xml
rename to automotive/automotive-lib/src/main/res/drawable/toolbar_back_ripple_background.xml
index 2deabd2cf..d7f5ac855 100644
--- a/automotive/src/main/res/drawable/sign_in_toolbar_back_ripple_background.xml
+++ b/automotive/automotive-lib/src/main/res/drawable/toolbar_back_ripple_background.xml
@@ -1,12 +1,12 @@
+ android:radius="@dimen/toolbar_nav_button_size" />
diff --git a/automotive/automotive-lib/src/main/res/drawable/toolbar_button_background.xml b/automotive/automotive-lib/src/main/res/drawable/toolbar_button_background.xml
new file mode 100644
index 000000000..d56787784
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/drawable/toolbar_button_background.xml
@@ -0,0 +1,25 @@
+
+
+
+ -
+
+
+
+
+
+
diff --git a/automotive/automotive-lib/src/main/res/layout/check_box_list_item.xml b/automotive/automotive-lib/src/main/res/layout/check_box_list_item.xml
new file mode 100644
index 000000000..42919ee4b
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/layout/check_box_list_item.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/automotive/src/main/res/layout/preference_category.xml b/automotive/automotive-lib/src/main/res/layout/list_preference.xml
similarity index 50%
rename from automotive/src/main/res/layout/preference_category.xml
rename to automotive/automotive-lib/src/main/res/layout/list_preference.xml
index d843352e9..95da11579 100644
--- a/automotive/src/main/res/layout/preference_category.xml
+++ b/automotive/automotive-lib/src/main/res/layout/list_preference.xml
@@ -1,6 +1,6 @@
-
+ -->
-
+
+
+
+
+
-
\ No newline at end of file
diff --git a/automotive/automotive-lib/src/main/res/layout/preference.xml b/automotive/automotive-lib/src/main/res/layout/preference.xml
new file mode 100644
index 000000000..37f29ce3b
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/layout/preference.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/automotive/automotive-lib/src/main/res/layout/preference_category.xml b/automotive/automotive-lib/src/main/res/layout/preference_category.xml
new file mode 100644
index 000000000..eeaf07bd6
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/layout/preference_category.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/automotive/automotive-lib/src/main/res/layout/preference_edit_text.xml b/automotive/automotive-lib/src/main/res/layout/preference_edit_text.xml
new file mode 100644
index 000000000..73dce370b
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/layout/preference_edit_text.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/automotive/automotive-lib/src/main/res/layout/preference_seekbar.xml b/automotive/automotive-lib/src/main/res/layout/preference_seekbar.xml
new file mode 100644
index 000000000..275e3dfd9
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/layout/preference_seekbar.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/automotive/automotive-lib/src/main/res/layout/radio_button_list_item.xml b/automotive/automotive-lib/src/main/res/layout/radio_button_list_item.xml
new file mode 100644
index 000000000..cdeb01a0c
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/layout/radio_button_list_item.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/automotive/automotive-lib/src/main/res/values/dimens.xml b/automotive/automotive-lib/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..df5b5051e
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/values/dimens.xml
@@ -0,0 +1,42 @@
+
+
+
+ 20dp
+ 24dp
+ 44dp
+ 22dp
+ 96dp
+
+ 116dp
+ 32dp
+
+ 32dp
+ 32dp
+ 20dp
+ 20dp
+ 32dp
+
+
+ 32dp
+ 16dp
+ 16dp
+ 112dp
+ 48dp
+
+ 32sp
+ 26sp
+
diff --git a/automotive/automotive-lib/src/main/res/values/strings.xml b/automotive/automotive-lib/src/main/res/values/strings.xml
new file mode 100644
index 000000000..552cd04b3
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/values/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Automotive Library
+
diff --git a/automotive/automotive-lib/src/main/res/values/styles.xml b/automotive/automotive-lib/src/main/res/values/styles.xml
new file mode 100644
index 000000000..608ba4f43
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/values/styles.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/automotive/automotive-lib/src/main/res/values/themes.xml b/automotive/automotive-lib/src/main/res/values/themes.xml
new file mode 100644
index 000000000..ca109b034
--- /dev/null
+++ b/automotive/automotive-lib/src/main/res/values/themes.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/automotive/automotive-lib/src/test/java/com/example/android/uamp/automotive/lib/ExampleUnitTest.kt b/automotive/automotive-lib/src/test/java/com/example/android/uamp/automotive/lib/ExampleUnitTest.kt
new file mode 100644
index 000000000..b8f1c1f65
--- /dev/null
+++ b/automotive/automotive-lib/src/test/java/com/example/android/uamp/automotive/lib/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.example.android.uamp.automotive.lib
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/automotive/build.gradle b/automotive/build.gradle
index 5e5e87c34..52a7265db 100644
--- a/automotive/build.gradle
+++ b/automotive/build.gradle
@@ -49,16 +49,15 @@ android {
dependencies {
implementation project(':common')
-
+ implementation project(':automotive:automotive-lib')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.core:core-ktx:$androidx_core_ktx_version"
- implementation "androidx.preference:preference:$androidx_preference_version"
- implementation "androidx.car:car:$androidx_car_version"
implementation "androidx.constraintlayout:constraintlayout:$constraint_layout_version"
+ implementation "androidx.preference:preference:$androidx_preference_version"
implementation "androidx.appcompat:appcompat:$androidx_app_compat_version"
implementation "androidx.lifecycle:lifecycle-extensions:$arch_lifecycle_version"
-
+ implementation "com.google.android.material:material:$material_version"
implementation "com.google.android.gms:play-services-auth:$play_services_auth_version"
testImplementation "junit:junit:$junit_version"
diff --git a/automotive/src/main/AndroidManifest.xml b/automotive/src/main/AndroidManifest.xml
index 622c0fdf2..94fcf05c8 100644
--- a/automotive/src/main/AndroidManifest.xml
+++ b/automotive/src/main/AndroidManifest.xml
@@ -51,7 +51,7 @@
diff --git a/automotive/src/main/java/com/example/android/uamp/automotive/SettingsActivity.kt b/automotive/src/main/java/com/example/android/uamp/automotive/SettingsActivity.kt
index 6d74507ae..f28d4b492 100644
--- a/automotive/src/main/java/com/example/android/uamp/automotive/SettingsActivity.kt
+++ b/automotive/src/main/java/com/example/android/uamp/automotive/SettingsActivity.kt
@@ -42,11 +42,6 @@ class SettingsActivity : AppCompatActivity() {
.commit()
}
- override fun onBackPressed() {
- super.onBackPressed()
- finish()
- }
-
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
diff --git a/automotive/src/main/res/drawable/default_button_background.xml b/automotive/src/main/res/drawable/default_button_background.xml
index d576414a5..0535a2469 100644
--- a/automotive/src/main/res/drawable/default_button_background.xml
+++ b/automotive/src/main/res/drawable/default_button_background.xml
@@ -20,7 +20,7 @@
android:color="?attr/colorControlHighlight">
-
-
+
diff --git a/automotive/src/main/res/drawable/ic_settings_wifi.xml b/automotive/src/main/res/drawable/ic_settings_wifi.xml
new file mode 100644
index 000000000..65e2dd5c6
--- /dev/null
+++ b/automotive/src/main/res/drawable/ic_settings_wifi.xml
@@ -0,0 +1,12 @@
+
+
+
\ No newline at end of file
diff --git a/automotive/src/main/res/layout/activity_settings.xml b/automotive/src/main/res/layout/activity_settings.xml
index 590ea8cda..1c5b1e534 100644
--- a/automotive/src/main/res/layout/activity_settings.xml
+++ b/automotive/src/main/res/layout/activity_settings.xml
@@ -22,19 +22,18 @@
+ android:layout_height="wrap_content"
+ android:background="@android:color/transparent">
+ android:layout_height="?attr/actionBarSize"/>
+ android:layout_height="match_parent" />
diff --git a/automotive/src/main/res/values/arrays.xml b/automotive/src/main/res/values/arrays.xml
new file mode 100644
index 000000000..5475c985b
--- /dev/null
+++ b/automotive/src/main/res/values/arrays.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+ - Choose me!
+
+ - No, me!
+
+ - What about me?!
+
+
+
+
+
+ - alpha
+
+ - beta
+
+ - charlie
+
+
\ No newline at end of file
diff --git a/automotive/src/main/res/values/dimens.xml b/automotive/src/main/res/values/dimens.xml
index c0c547aa8..4dd7307b4 100644
--- a/automotive/src/main/res/values/dimens.xml
+++ b/automotive/src/main/res/values/dimens.xml
@@ -23,12 +23,11 @@
26sp
158dp
+ 4dp
56dp
56dp
- 24dp
- 48dp
- 96dp
+ @dimen/toolbar_height
4dp
2dp
diff --git a/automotive/src/main/res/values/strings.xml b/automotive/src/main/res/values/strings.xml
index bda2ae70a..f8fc91bc3 100644
--- a/automotive/src/main/res/values/strings.xml
+++ b/automotive/src/main/res/values/strings.xml
@@ -46,4 +46,53 @@
https://chart.apis.google.com/chart?cht=qr&chs=392x392&chl=https://www.youtube.com/watch?v=8I8mCFYYfdk
YOUR_SERVER_CLIENT_ID
+
+
+ Basic attributes
+
+ Preference
+
+ Simple preference with no special attributes
+
+ Very stylish preference
+
+ Define style tags such as <b> in a string resource to customize a preference\'s text
+
+ Icon preference
+
+ Define a drawable to display it at the start of the preference
+
+ Single line title preference - no matter how long the title is it will never wrap to multiple lines
+
+ This title will be ellipsized instead of wrapping to another line
+
+ Single line preference - no summary
+
+ Widgets
+
+ Checkbox preference
+
+ Tap anywhere in this preference to toggle state
+
+ Switch preference
+
+ Tap anywhere in this preference to toggle state
+
+ Seekbar preference
+
+ Dialogs
+
+ EditText preference
+
+ This title can be changed!
+
+ List preference
+
+ Choose one option!
+
+ Multi-select list preference
+
+ Shows a dialog with multiple choice options
+
+ Choose some options!
diff --git a/automotive/src/main/res/values/styles.xml b/automotive/src/main/res/values/styles.xml
index 166e76e2f..9d2a8404b 100644
--- a/automotive/src/main/res/values/styles.xml
+++ b/automotive/src/main/res/values/styles.xml
@@ -19,34 +19,16 @@
-
-
-
-
-
-
-
+
-
+
-
+
\ No newline at end of file
diff --git a/automotive/src/main/res/xml/preferences.xml b/automotive/src/main/res/xml/preferences.xml
index 68ec51720..b29bf1811 100644
--- a/automotive/src/main/res/xml/preferences.xml
+++ b/automotive/src/main/res/xml/preferences.xml
@@ -15,17 +15,89 @@
~ limitations under the License.
-->
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
-
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 63c75b5c2..54222721a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,9 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
-buildscript {
+buildscript {
+ ext.kotlin_version = '1.3.50'
+
ext {
// App SDK versions.
compileSdkVersion = 28
@@ -28,7 +30,7 @@ buildscript {
androidx_car_version = '1.0.0-alpha7'
androidx_core_ktx_version = '1.0.2'
androidx_media_version = '1.0.1'
- androidx_preference_version = '1.0.0'
+ androidx_preference_version = '1.1.0'
androidx_test_runner_version = '1.1.1'
arch_lifecycle_version = '2.0.0'
constraint_layout_version = '1.1.3'
@@ -43,6 +45,7 @@ buildscript {
kotlin_coroutines_version = '1.1.0'
play_services_auth_version = '17.0.0'
recycler_view_version = '1.0.0'
+ material_version = '1.0.0'
robolectric_version = '4.2'
test_runner_version = '1.1.0'
}
diff --git a/settings.gradle b/settings.gradle
index 5edff895c..d320a3a01 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -39,4 +39,4 @@ if (extraSettings.exists()) {
apply from: extraSettings
}
-include ':app', ':common', ':automotive'
+include ':app', ':common', ':automotive', ':automotive:automotive-lib'