Merge pi-dev-plus-aosp-without-vendor into stage-aosp-master

Bug: 79597307
Change-Id: Icdda8a0c892974d93e9a9f15c01e91dc77b724cb
diff --git a/accessibility/CheckableLayout/gradle/wrapper/gradle-wrapper.properties b/accessibility/CheckableLayout/gradle/wrapper/gradle-wrapper.properties
index ef44a88..45ff7e4 100644
--- a/accessibility/CheckableLayout/gradle/wrapper/gradle-wrapper.properties
+++ b/accessibility/CheckableLayout/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties b/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties
index 22aa0ef..7b9b654 100644
--- a/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties
+++ b/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties b/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties
index 819aeb4..ade4cee 100644
--- a/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties
+++ b/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/admin/BasicManagedProfile/gradle/wrapper/gradle-wrapper.properties b/admin/BasicManagedProfile/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/admin/BasicManagedProfile/gradle/wrapper/gradle-wrapper.properties
+++ b/admin/BasicManagedProfile/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.properties b/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.properties
index 6db5b79..e69441a 100644
--- a/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.properties
+++ b/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/admin/NfcProvisioning/gradle/wrapper/gradle-wrapper.properties b/admin/NfcProvisioning/gradle/wrapper/gradle-wrapper.properties
index 6bf185d..276ce8b 100644
--- a/admin/NfcProvisioning/gradle/wrapper/gradle-wrapper.properties
+++ b/admin/NfcProvisioning/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/background/JobScheduler/gradle/wrapper/gradle-wrapper.properties b/background/JobScheduler/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/background/JobScheduler/gradle/wrapper/gradle-wrapper.properties
+++ b/background/JobScheduler/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/.google/packaging.yaml b/background/JobScheduler/kotlinApp/.google/packaging.yaml
new file mode 100644
index 0000000..536f91b
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/.google/packaging.yaml
@@ -0,0 +1,13 @@
+
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [Background]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-JobScheduler
+license:      apache2
diff --git a/background/JobScheduler/kotlinApp/CONTRIB.md b/background/JobScheduler/kotlinApp/CONTRIB.md
new file mode 100644
index 0000000..14a4fcf
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/CONTRIB.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual CLA]
+    (https://developers.google.com/open-source/cla/individual).
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA]
+    (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+   Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+   you are contributing. Refer to the
+   [Android Code Style Guide]
+   (https://source.android.com/source/code-style.html) for the
+   recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/background/JobScheduler/kotlinApp/README.md b/background/JobScheduler/kotlinApp/README.md
new file mode 100644
index 0000000..319cf2d
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/README.md
@@ -0,0 +1,60 @@
+
+Android JobScheduler Sample (Kotlin)
+====================================
+
+Demonstration of the JobScheduler API, which provides an interface for scheduling
+background tasks when certain tasks apply.
+
+To understand how this sample works, try these different scenarios:
+
+- Unplug device, schedule a task that requires the device to be plugged in. Job will start when the
+device is plugged in.
+- Set a delay of 10 seconds and press back. The activity and service are finished but the service is
+launched again in 10 seconds (logcat will show debug messages).
+- Set a delay of 5 seconds and a work duration of 10 seconds. Schedule job and press the
+back button. Open the activity again after 6 seconds. The activity will show the onStopTask even
+though both activity and service were shut down.
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-JobScheduler
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2017 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/background/JobScheduler/kotlinApp/app/build.gradle b/background/JobScheduler/kotlinApp/app/build.gradle
new file mode 100644
index 0000000..f3bd616
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/build.gradle
@@ -0,0 +1,27 @@
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion 27
+    defaultConfig {
+        applicationId "com.example.android.jobscheduler"
+        minSdkVersion 21
+        targetSdkVersion 27
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:27.0.0"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+}
\ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/AndroidManifest.xml b/background/JobScheduler/kotlinApp/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5230d84
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.jobscheduler">
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+    <application
+        android:allowBackup="false"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name"
+            android:windowSoftInputMode="stateHidden" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <service
+            android:name=".MyJobService"
+            android:permission="android.permission.BIND_JOB_SERVICE"
+            android:exported="true"/>
+    </application>
+
+</manifest>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/ActivityExtensions.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/ActivityExtensions.kt
new file mode 100644
index 0000000..39a9d7e
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/ActivityExtensions.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 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 com.example.android.jobscheduler
+
+import android.app.Activity
+import android.widget.Toast
+
+/**
+ * Helper extension function for showing a [Toast]
+ */
+fun Activity.showToast(text: String) {
+    Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
+}
\ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/Constants.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/Constants.kt
new file mode 100644
index 0000000..90fc00f
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/Constants.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 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.
+ */
+
+@file:JvmName("Constants")
+@file:Suppress("PropertyName")
+
+package com.example.android.jobscheduler
+
+@JvmField val MSG_UNCOLOR_START = 0
+@JvmField val MSG_UNCOLOR_STOP = 1
+@JvmField val MSG_COLOR_START = 2
+@JvmField val MSG_COLOR_STOP = 3
+
+@JvmField val MESSENGER_INTENT_KEY = "${BuildConfig.APPLICATION_ID}.MESSENGER_INTENT_KEY"
+@JvmField val WORK_DURATION_KEY = "${BuildConfig.APPLICATION_ID}.WORK_DURATION_KEY"
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/IncomingMessageHandler.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/IncomingMessageHandler.kt
new file mode 100644
index 0000000..9d5b114
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/IncomingMessageHandler.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 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 com.example.android.jobscheduler
+
+import android.os.Handler
+import android.os.Message
+import android.os.Messenger
+import android.support.v4.content.ContextCompat.getColor
+import android.view.View
+import android.widget.TextView
+import java.lang.ref.WeakReference
+import java.util.concurrent.TimeUnit
+
+/**
+ * A [Handler] allows you to send messages associated with a thread. A [Messenger]
+ * uses this handler to communicate from [MyJobService]. It's also used to make
+ * the start and stop views blink for a short period of time.
+ */
+internal class IncomingMessageHandler(activity: MainActivity) : Handler() {
+
+    // Prevent possible leaks with a weak reference.
+    private val mainActivity: WeakReference<MainActivity> = WeakReference(activity)
+
+    override fun handleMessage(msg: Message) {
+        val mainActivity = mainActivity.get() ?: return
+        val showStartView = mainActivity.findViewById<View>(R.id.onstart_textview)
+        val showStopView = mainActivity.findViewById<View>(R.id.onstop_textview)
+        when (msg.what) {
+            /*
+             * Receives callback from the service when a job has landed
+             * on the app. Turns on indicator and sends a message to turn it off after
+             * a second.
+             */
+            MSG_COLOR_START -> {
+                // Start received, turn on the indicator and show text.
+                showStartView.setBackgroundColor(getColor(mainActivity, R.color.start_received))
+                updateParamsTextView(msg.obj, "started")
+                sendMessageDelayed(Message.obtain(this, MSG_UNCOLOR_START),
+                        TimeUnit.SECONDS.toMillis(1))
+            }
+            /*
+             * Receives callback from the service when a job that previously landed on the
+             * app must stop executing. Turns on indicator and sends a message to turn it
+             * off after two seconds.
+             */
+            MSG_COLOR_STOP -> {
+                // Stop received, turn on the indicator and show text.
+                showStopView.setBackgroundColor(getColor(mainActivity, R.color.stop_received))
+                updateParamsTextView(msg.obj, "stopped")
+                sendMessageDelayed(obtainMessage(MSG_UNCOLOR_STOP), TimeUnit.SECONDS.toMillis(1))
+            }
+            MSG_UNCOLOR_START -> {
+                uncolorButtonAndClearText(showStartView, mainActivity)
+            }
+            MSG_UNCOLOR_STOP -> {
+                uncolorButtonAndClearText(showStopView, mainActivity)
+            }
+        }
+    }
+
+    private fun uncolorButtonAndClearText(textView: View, activity: MainActivity) {
+        textView.setBackgroundColor(getColor(activity, R.color.none_received))
+        updateParamsTextView()
+    }
+
+    private fun updateParamsTextView(jobId: Any? = null, action: String = "") {
+        val mainActivity = mainActivity.get() ?: return
+        val paramsTextView = mainActivity.findViewById<TextView>(R.id.task_params)
+        if (jobId == null) {
+            paramsTextView.text = ""
+            return
+        }
+        paramsTextView.text = mainActivity.getString(R.string.job_status, jobId.toString(), action)
+    }
+}
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MainActivity.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MainActivity.kt
new file mode 100644
index 0000000..b28d5c4
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MainActivity.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright 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 com.example.android.jobscheduler
+
+import android.app.Activity
+import android.app.job.JobInfo
+import android.app.job.JobScheduler
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.Messenger
+import android.os.PersistableBundle
+import android.util.Log
+import android.widget.Button
+import android.widget.CheckBox
+import android.widget.EditText
+import android.widget.RadioButton
+import java.util.concurrent.TimeUnit
+
+/**
+ * Schedules and configures jobs to be executed by a [JobScheduler].
+ *
+ * [MyJobService] can send messages to this via a [Messenger]
+ * that is sent in the Intent that starts the Service.
+ */
+class MainActivity : Activity() {
+
+    lateinit private var anyConnectivityRadioButton: RadioButton
+    lateinit private var deadlineEditText: EditText
+    lateinit private var delayEditText: EditText
+    lateinit private var durationTimeEditText: EditText
+    lateinit private var requiresChargingCheckBox: CheckBox
+    lateinit private var requiresIdleCheckbox: CheckBox
+    lateinit private var wiFiConnectivityRadioButton: RadioButton
+
+    // Handler for incoming messages from the service.
+    lateinit private var handler: IncomingMessageHandler
+    lateinit private var serviceComponent: ComponentName
+    private var jobId = 0
+
+    public override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.sample_main)
+
+        anyConnectivityRadioButton = findViewById(R.id.checkbox_any)
+        deadlineEditText = findViewById(R.id.deadline_time)
+        delayEditText = findViewById(R.id.delay_time)
+        durationTimeEditText = findViewById(R.id.duration_time)
+        requiresChargingCheckBox = findViewById(R.id.checkbox_charging)
+        requiresIdleCheckbox = findViewById(R.id.checkbox_idle)
+        wiFiConnectivityRadioButton = findViewById(R.id.checkbox_unmetered)
+
+        handler = IncomingMessageHandler(this)
+        serviceComponent = ComponentName(this, MyJobService::class.java)
+
+        findViewById<Button>(R.id.cancel_button).setOnClickListener { cancelAllJobs() }
+        findViewById<Button>(R.id.finished_button).setOnClickListener { finishJob() }
+        findViewById<Button>(R.id.schedule_button).setOnClickListener { scheduleJob() }
+    }
+
+    override fun onStop() {
+        // A service can be "started" and/or "bound". In this case, it's "started" by this Activity
+        // and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
+        // to stopService() won't prevent scheduled jobs to be processed. However, failing
+        // to call stopService() would keep it alive indefinitely.
+        stopService(Intent(this, MyJobService::class.java))
+        super.onStop()
+    }
+
+    override fun onStart() {
+        super.onStart()
+        // Start service and provide it a way to communicate with this class.
+        val startServiceIntent = Intent(this, MyJobService::class.java)
+        val messengerIncoming = Messenger(handler)
+        startServiceIntent.putExtra(MESSENGER_INTENT_KEY, messengerIncoming)
+        startService(startServiceIntent)
+    }
+
+    /**
+     * Executed when user clicks on SCHEDULE JOB.
+     */
+    private fun scheduleJob() {
+        val builder = JobInfo.Builder(jobId++, serviceComponent)
+
+        val delay = delayEditText.text.toString()
+        if (delay.isNotEmpty()) {
+            builder.setMinimumLatency(delay.toLong() * TimeUnit.SECONDS.toMillis(1))
+        }
+
+        val deadline = deadlineEditText.text.toString()
+        if (deadline.isNotEmpty()) {
+            builder.setOverrideDeadline(deadline.toLong() * TimeUnit.SECONDS.toMillis(1))
+        }
+
+        if (wiFiConnectivityRadioButton.isChecked) {
+            builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
+        } else if (anyConnectivityRadioButton.isChecked) {
+            builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+        }
+
+        // Extras, work duration.
+        val extras = PersistableBundle()
+        var workDuration = durationTimeEditText.text.toString()
+        if (workDuration.isEmpty()) workDuration = "1"
+        extras.putLong(WORK_DURATION_KEY, workDuration.toLong() * TimeUnit.SECONDS.toMillis(1))
+
+        // Finish configuring the builder
+        builder.run {
+            setRequiresDeviceIdle(requiresIdleCheckbox.isChecked)
+            setRequiresCharging(requiresChargingCheckBox.isChecked)
+            setExtras(extras)
+        }
+
+        // Schedule job
+        Log.d(TAG, "Scheduling job")
+        (getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler).schedule(builder.build())
+    }
+
+    /**
+     * Executed when user clicks on CANCEL ALL.
+     */
+    private fun cancelAllJobs() {
+        (getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler).cancelAll()
+        showToast(getString(R.string.all_jobs_cancelled))
+    }
+
+    /**
+     * Executed when user clicks on FINISH LAST TASK.
+     */
+    private fun finishJob() {
+        val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
+        val allPendingJobs = jobScheduler.allPendingJobs
+        if (allPendingJobs.size > 0) {
+            // Finish the last one.
+            // Example: If jobs a, b, and c are queued in that order, this method will cancel job c.
+            val id = allPendingJobs.first().id
+            jobScheduler.cancel(id)
+            showToast(getString(R.string.cancelled_job, id))
+        } else {
+            showToast(getString(R.string.no_jobs_to_cancel))
+        }
+    }
+
+    companion object {
+        private val TAG = "MainActivity"
+    }
+}
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MyJobService.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MyJobService.kt
new file mode 100644
index 0000000..3c6cc54
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MyJobService.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright 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 com.example.android.jobscheduler
+
+import android.app.Service
+import android.app.job.JobParameters
+import android.app.job.JobService
+import android.content.Intent
+import android.os.Handler
+import android.os.Message
+import android.os.Messenger
+import android.os.RemoteException
+import android.util.Log
+
+/**
+ * Service to handle callbacks from the JobScheduler. Requests scheduled with the JobScheduler
+ * ultimately land on this service's "onStartJob" method. It runs jobs for a specific amount of time
+ * and finishes them. It keeps the activity updated with changes via a Messenger.
+ */
+class MyJobService : JobService() {
+
+    private var activityMessenger: Messenger? = null
+
+    /**
+     * When the app's MainActivity is created, it starts this service. This is so that the
+     * activity and this service can communicate back and forth. See "setUiCallback()"
+     */
+    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+        activityMessenger = intent.getParcelableExtra(MESSENGER_INTENT_KEY)
+        return Service.START_NOT_STICKY
+    }
+
+    override fun onStartJob(params: JobParameters): Boolean {
+        // The work that this service "does" is simply wait for a certain duration and finish
+        // the job (on another thread).
+        sendMessage(MSG_COLOR_START, params.jobId)
+
+        // Uses a Handler to delay the execution of jobFinished().
+        val duration = params.extras.getLong(WORK_DURATION_KEY)
+        Handler().postDelayed({
+            sendMessage(MSG_COLOR_STOP, params.jobId)
+            jobFinished(params, false)
+        }, duration)
+        Log.i(TAG, "on start job: ${params.jobId}")
+
+        // Return true as there's more work to be done with this job.
+        return true
+    }
+
+    override fun onStopJob(params: JobParameters): Boolean {
+        // Stop tracking these job parameters, as we've 'finished' executing.
+        sendMessage(MSG_COLOR_STOP, params.jobId)
+        Log.i(TAG, "on stop job: ${params.jobId}")
+
+        // Return false to drop the job.
+        return false
+    }
+
+    private fun sendMessage(messageID: Int, params: Any?) {
+        // If this service is launched by the JobScheduler, there's no callback Messenger. It
+        // only exists when the MainActivity calls startService() with the callback in the Intent.
+        if (activityMessenger == null) {
+            Log.d(TAG, "Service is bound, not started. There's no callback to send a message to.")
+            return
+        }
+        val message = Message.obtain()
+        message.run {
+            what = messageID
+            obj = params
+        }
+        try {
+            activityMessenger?.send(message)
+        } catch (e: RemoteException) {
+            Log.e(TAG, "Error passing service object back to activity.")
+        }
+    }
+
+    companion object {
+        private val TAG = "MyJobService"
+    }
+}
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/ic_launcher.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..9cb5f74
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-mdpi/ic_launcher.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..869355b
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xhdpi/ic_launcher.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..679fc16
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..1734fd3
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/layout/sample_main.xml b/background/JobScheduler/kotlinApp/app/src/main/res/layout/sample_main.xml
new file mode 100644
index 0000000..84a2194
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/layout/sample_main.xml
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/layout_height">
+
+            <TextView
+                android:id="@+id/onstart_textview"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_margin="@dimen/textview_margin"
+                android:layout_weight="1"
+                android:background="@color/none_received"
+                android:gravity="center"
+                android:text="@string/onstarttask" />
+
+            <TextView
+                android:id="@+id/onstop_textview"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_margin="@dimen/textview_margin"
+                android:layout_weight="1"
+                android:background="@color/none_received"
+                android:gravity="center"
+                android:text="@string/onstoptask" />
+
+        </LinearLayout>
+
+        <TextView
+            android:id="@+id/task_params"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_marginBottom="@dimen/textview_bottom_margin"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:padding="@dimen/textview_margin"
+            android:textSize="@dimen/large_text_size" />
+
+        <Button
+            android:id="@+id/finished_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="@dimen/button_padding"
+            android:layout_marginBottom="@dimen/button_bottom_margin"
+            android:layout_marginLeft="@dimen/button_horizontal_margins"
+            android:layout_marginRight="@dimen/button_horizontal_margins"
+            android:text="@string/finish_job_button_text" />
+
+        <TableLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="@dimen/table_margin">
+
+            <TableRow
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_marginEnd="@dimen/textview_margin"
+                    android:labelFor="@id/duration_time"
+                    android:gravity="end|center_vertical"
+                    android:text="@string/work_duration"
+                    android:textSize="@dimen/default_text_size" />
+
+                <EditText
+                    android:id="@+id/duration_time"
+                    android:layout_width="@dimen/edittext_width"
+                    android:layout_height="wrap_content"
+                    android:inputType="number"
+                    android:text="@string/default_duration_time" />
+
+            </TableRow>
+
+            <TableRow
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_marginEnd="@dimen/textview_margin"
+                    android:gravity="end|center_vertical"
+                    android:text="@string/connectivity"
+                    android:textSize="@dimen/default_text_size" />
+
+                <RadioGroup
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <RadioButton
+                        android:id="@+id/checkbox_any"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:checked="true"
+                        android:text="@string/any" />
+
+                    <RadioButton
+                        android:id="@+id/checkbox_unmetered"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/unmetered" />
+
+                </RadioGroup>
+
+            </TableRow>
+
+            <TableRow
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_marginEnd="@dimen/textview_margin"
+                    android:gravity="end|center_vertical"
+                    android:text="@string/delay"
+                    android:textSize="@dimen/default_text_size" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:orientation="horizontal">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:labelFor="@id/delay_time"
+                        android:text="@string/timing" />
+
+                    <EditText
+                        android:id="@+id/delay_time"
+                        android:layout_width="@dimen/edittext_width"
+                        android:layout_height="wrap_content"
+                        android:inputType="number"
+                        android:text="@string/default_delay_time" />
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:labelFor="@id/deadline_time"
+                        android:text="@string/deadline"
+                        android:textSize="@dimen/default_text_size" />
+
+                    <EditText
+                        android:id="@+id/deadline_time"
+                        android:layout_width="@dimen/edittext_width"
+                        android:layout_height="wrap_content"
+                        android:inputType="number"
+                        android:text="@string/default_deadline_time" />
+
+                </LinearLayout>
+
+            </TableRow>
+
+            <TableRow
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_weight="1">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_marginEnd="@dimen/tablerow_margin_end"
+                    android:gravity="end|center_vertical"
+                    android:text="@string/charging_caption"
+                    android:textSize="@dimen/default_text_size" />
+
+                <CheckBox
+                    android:id="@+id/checkbox_charging"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/charging_text" />
+
+            </TableRow>
+
+            <TableRow
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_weight="1">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_marginEnd="@dimen/tablerow_margin_end"
+                    android:gravity="end|center_vertical"
+                    android:text="@string/idle_caption" />
+
+                <CheckBox
+                    android:id="@+id/checkbox_idle"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/idle_mode_text" />
+
+            </TableRow>
+
+        </TableLayout>
+
+        <Button
+            android:id="@+id/schedule_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/button_top_margin"
+            android:layout_marginLeft="@dimen/button_horizontal_margins"
+            android:layout_marginRight="@dimen/button_horizontal_margins"
+            android:text="@string/schedule_job_button_text" />
+        <Button
+            android:id="@+id/cancel_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/button_horizontal_margins"
+            android:layout_marginRight="@dimen/button_horizontal_margins"
+            android:text="@string/cancel_all_jobs_button_text" />
+
+    </LinearLayout>
+
+</ScrollView>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..2144796
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..3dd911c
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/styles.xml
new file mode 100644
index 0000000..1903546
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/styles.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/sample-styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/template-styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..000ff51
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/template-styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+    <!-- Activity themes -->
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-v14/styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-v14/styles.xml
new file mode 100644
index 0000000..9c21dbe
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-v14/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/sample-styles.xml and
+        res/values-v11/sample-styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml
new file mode 100644
index 0000000..28215b7
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+    <!-- Activity themes -->
+    <style name="Theme.Base" parent="android:Theme.Material.Light">
+    </style>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/base-strings.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/base-strings.xml
new file mode 100644
index 0000000..034a3bf
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/base-strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+    <string name="app_name">JobScheduler</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            Demonstration of the JobScheduler API, which provides an interface for scheduling
+            background tasks when certain tasks apply.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/color.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/color.xml
new file mode 100644
index 0000000..5431f76
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+    <color name="none_received">#999999</color>
+    <color name="start_received">#00FF00</color>
+    <color name="stop_received">#FF0000</color>
+</resources>
\ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/dimens.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..859937f
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/dimens.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+    <dimen name="default_text_size">14sp</dimen>
+    <dimen name="large_text_size">20sp</dimen>
+    <dimen name="button_horizontal_margins">40dp</dimen>
+    <dimen name="button_top_margin">20dp</dimen>
+    <dimen name="tablerow_margin_end">12dp</dimen>
+    <dimen name="edittext_width">48dp</dimen>
+    <dimen name="textview_margin">12dp</dimen>
+    <dimen name="textview_bottom_margin">10dp</dimen>
+    <dimen name="button_padding">20dp</dimen>
+    <dimen name="button_bottom_margin">5dp</dimen>
+    <dimen name="layout_height">100dp</dimen>
+    <dimen name="table_margin">8dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/strings.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..f0e26b7
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/strings.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+    <string name="onstoptask">onStopTask</string>
+    <string name="onstarttask">onStartTask</string>
+    <string name="defaultparamtext">task params will show up here.</string>
+    <string name="schedule_job_button_text">Schedule Job</string>
+    <string name="cancel_all_jobs_button_text">Cancel all</string>
+    <string name="finish_job_button_text">Finish last task</string>
+    <string name="idle_mode_text">Requires device in idle mode.</string>
+    <string name="charging_caption">Charging:</string>
+    <string name="charging_text">Requires device plugged in.</string>
+    <string name="idle_caption">Idle:</string>
+    <string name="connectivity">Connectivity:</string>
+    <string name="any">Any</string>
+    <string name="unmetered">WiFi</string>
+    <string name="timing">Timing:</string>
+    <string name="delay">Delay:</string>
+    <string name="deadline">Deadline:</string>
+    <string name="work_duration">Work duration:</string>
+    <string name="cancelled_job">Cancelled job %d</string>
+    <string name="no_jobs_to_cancel">No jobs to cancel</string>
+    <string name="all_jobs_cancelled">All jobs cancelled</string>
+    <string name="job_status">Job ID %s %s</string>
+    <string name="default_duration_time">2</string>
+    <string name="default_delay_time">0</string>
+    <string name="default_deadline_time">15</string>
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..c174da4
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/styles.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+    <!--
+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Light">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/template-dimens.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/template-dimens.xml
new file mode 100644
index 0000000..30a0d8d
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/template-dimens.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/template-styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/template-styles.xml
new file mode 100644
index 0000000..357da34
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/template-styles.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/build.gradle b/background/JobScheduler/kotlinApp/build.gradle
new file mode 100644
index 0000000..5dc45d1
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/build.gradle
@@ -0,0 +1,22 @@
+buildscript {
+    ext.kotlin_version = '1.1.60'
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.0'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..28055da
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Nov 07 16:05:05 PST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/background/JobScheduler/kotlinApp/gradlew b/background/JobScheduler/kotlinApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/background/JobScheduler/kotlinApp/gradlew.bat b/background/JobScheduler/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/background/JobScheduler/kotlinApp/packaging.yaml b/background/JobScheduler/kotlinApp/packaging.yaml
new file mode 100644
index 0000000..edef14f
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status:       PUBLISHED
+technologies: [Android]
+categories:   [Background]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       googlesamples/android-JobScheduler
+level:        BEGINNER
+icon:         JobSchedulerSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license:      apache2
diff --git a/background/JobScheduler/kotlinApp/settings.gradle b/background/JobScheduler/kotlinApp/settings.gradle
new file mode 100644
index 0000000..4c90568
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'app'
diff --git a/background/alarms/RepeatingAlarm/Application/build.gradle b/background/alarms/RepeatingAlarm/Application/build.gradle
index 194379f..61474dc 100644
--- a/background/alarms/RepeatingAlarm/Application/build.gradle
+++ b/background/alarms/RepeatingAlarm/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/background/alarms/RepeatingAlarm/gradle/wrapper/gradle-wrapper.properties b/background/alarms/RepeatingAlarm/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/background/alarms/RepeatingAlarm/gradle/wrapper/gradle-wrapper.properties
+++ b/background/alarms/RepeatingAlarm/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/bluetooth/BluetoothAdvertisements/gradle/wrapper/gradle-wrapper.properties b/connectivity/bluetooth/BluetoothAdvertisements/gradle/wrapper/gradle-wrapper.properties
index 75cf0fd..20f6c5a 100644
--- a/connectivity/bluetooth/BluetoothAdvertisements/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/bluetooth/BluetoothAdvertisements/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/bluetooth/BluetoothChat/gradle/wrapper/gradle-wrapper.properties b/connectivity/bluetooth/BluetoothChat/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/connectivity/bluetooth/BluetoothChat/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/bluetooth/BluetoothChat/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/bluetooth/BluetoothLeGatt/gradle/wrapper/gradle-wrapper.properties b/connectivity/bluetooth/BluetoothLeGatt/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/connectivity/bluetooth/BluetoothLeGatt/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/bluetooth/BluetoothLeGatt/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/network/BasicNetworking/gradle/wrapper/gradle-wrapper.properties b/connectivity/network/BasicNetworking/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/connectivity/network/BasicNetworking/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/network/BasicNetworking/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/network/NetworkConnect/gradle/wrapper/gradle-wrapper.properties b/connectivity/network/NetworkConnect/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/connectivity/network/NetworkConnect/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/network/NetworkConnect/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/nfc/BeamLargeFiles/gradle/wrapper/gradle-wrapper.properties b/connectivity/nfc/BeamLargeFiles/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/connectivity/nfc/BeamLargeFiles/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/nfc/BeamLargeFiles/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/nfc/CardEmulation/gradle/wrapper/gradle-wrapper.properties b/connectivity/nfc/CardEmulation/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/connectivity/nfc/CardEmulation/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/nfc/CardEmulation/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/nfc/CardReader/gradle/wrapper/gradle-wrapper.properties b/connectivity/nfc/CardReader/gradle/wrapper/gradle-wrapper.properties
index 9cf248f..c0c4211 100644
--- a/connectivity/nfc/CardReader/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/nfc/CardReader/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/sync/BasicSyncAdapter/gradle/wrapper/gradle-wrapper.properties b/connectivity/sync/BasicSyncAdapter/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/connectivity/sync/BasicSyncAdapter/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/sync/BasicSyncAdapter/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/connectivity/wifidirect/DirectP2P/gradle/wrapper/gradle-wrapper.properties b/connectivity/wifidirect/DirectP2P/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/connectivity/wifidirect/DirectP2P/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/wifidirect/DirectP2P/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/content/AutoBackupForApps/gradle/wrapper/gradle-wrapper.properties b/content/AutoBackupForApps/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/content/AutoBackupForApps/gradle/wrapper/gradle-wrapper.properties
+++ b/content/AutoBackupForApps/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/content/DirectShare/gradle/wrapper/gradle-wrapper.properties b/content/DirectShare/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/content/DirectShare/gradle/wrapper/gradle-wrapper.properties
+++ b/content/DirectShare/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/content/ShareActionProvider/gradle/wrapper/gradle-wrapper.properties b/content/ShareActionProvider/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/content/ShareActionProvider/gradle/wrapper/gradle-wrapper.properties
+++ b/content/ShareActionProvider/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/content/WidgetData/gradle/wrapper/gradle-wrapper.properties b/content/WidgetData/gradle/wrapper/gradle-wrapper.properties
index 9eaff01..71acacc 100644
--- a/content/WidgetData/gradle/wrapper/gradle-wrapper.properties
+++ b/content/WidgetData/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/content/contacts/BasicContactables/gradle/wrapper/gradle-wrapper.properties b/content/contacts/BasicContactables/gradle/wrapper/gradle-wrapper.properties
index cc77d43..566aa3b 100644
--- a/content/contacts/BasicContactables/gradle/wrapper/gradle-wrapper.properties
+++ b/content/contacts/BasicContactables/gradle/wrapper/gradle-wrapper.properties
@@ -4,4 +4,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/content/documentsUi/ContentProviderPaging/build.gradle b/content/documentsUi/ContentProviderPaging/build.gradle
index 66bc0b6..73a9672 100644
--- a/content/documentsUi/ContentProviderPaging/build.gradle
+++ b/content/documentsUi/ContentProviderPaging/build.gradle
@@ -4,7 +4,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/content/documentsUi/ContentProviderPaging/gradle/wrapper/gradle-wrapper.properties b/content/documentsUi/ContentProviderPaging/gradle/wrapper/gradle-wrapper.properties
index c5601e1..e8ff268 100644
--- a/content/documentsUi/ContentProviderPaging/gradle/wrapper/gradle-wrapper.properties
+++ b/content/documentsUi/ContentProviderPaging/gradle/wrapper/gradle-wrapper.properties
@@ -3,5 +3,5 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
 >>>>>>> ContentProviderPaging: Make kotlinApp module self-contained
diff --git a/content/documentsUi/ContentProviderPaging/kotlinApp/build.gradle b/content/documentsUi/ContentProviderPaging/kotlinApp/build.gradle
index 73f1fb4..94bedb1 100644
--- a/content/documentsUi/ContentProviderPaging/kotlinApp/build.gradle
+++ b/content/documentsUi/ContentProviderPaging/kotlinApp/build.gradle
@@ -5,7 +5,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
diff --git a/content/documentsUi/ContentProviderPaging/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/content/documentsUi/ContentProviderPaging/kotlinApp/gradle/wrapper/gradle-wrapper.properties
index 26b124f..c4f37a9 100644
--- a/content/documentsUi/ContentProviderPaging/kotlinApp/gradle/wrapper/gradle-wrapper.properties
+++ b/content/documentsUi/ContentProviderPaging/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/content/documentsUi/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionFragment.java b/content/documentsUi/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionFragment.java
index 075f39b..a617e99 100644
--- a/content/documentsUi/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionFragment.java
+++ b/content/documentsUi/DirectorySelection/Application/src/main/java/com/example/android/directoryselection/DirectorySelectionFragment.java
@@ -37,6 +37,7 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -198,8 +199,13 @@
         ContentResolver contentResolver = getActivity().getContentResolver();
         Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri,
                 DocumentsContract.getTreeDocumentId(uri));
-        Uri directoryUri = DocumentsContract
-                .createDocument(contentResolver, docUri, Document.MIME_TYPE_DIR, directoryName);
+        Uri directoryUri = null;
+        try {
+            directoryUri = DocumentsContract
+                    .createDocument(contentResolver, docUri, Document.MIME_TYPE_DIR, directoryName);
+        } catch (IOException e) {
+            Log.w(TAG, "IOException", e);
+        }
         if (directoryUri != null) {
             Log.i(TAG, String.format(
                     "Created directory : %s, Document Uri : %s, Created directory Uri : %s",
diff --git a/content/documentsUi/DirectorySelection/gradle/wrapper/gradle-wrapper.properties b/content/documentsUi/DirectorySelection/gradle/wrapper/gradle-wrapper.properties
index 8bdaa5d..d4585c3 100644
--- a/content/documentsUi/DirectorySelection/gradle/wrapper/gradle-wrapper.properties
+++ b/content/documentsUi/DirectorySelection/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/content/documentsUi/ScopedDirectoryAccess/Application/src/main/java/com/example/android/scopeddirectoryaccess/ScopedDirectoryAccessFragment.java b/content/documentsUi/ScopedDirectoryAccess/Application/src/main/java/com/example/android/scopeddirectoryaccess/ScopedDirectoryAccessFragment.java
index 23f1bb3..c19577c 100644
--- a/content/documentsUi/ScopedDirectoryAccess/Application/src/main/java/com/example/android/scopeddirectoryaccess/ScopedDirectoryAccessFragment.java
+++ b/content/documentsUi/ScopedDirectoryAccess/Application/src/main/java/com/example/android/scopeddirectoryaccess/ScopedDirectoryAccessFragment.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.storage.StorageManager;
@@ -30,6 +31,7 @@
 import android.support.v4.app.Fragment;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -38,6 +40,7 @@
 import android.widget.LinearLayout;
 import android.widget.Spinner;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -47,6 +50,8 @@
  */
 public class ScopedDirectoryAccessFragment extends Fragment {
 
+    private static final String TAG = "ScopedDirectorySample";
+
     private static final String DIRECTORY_ENTRIES_KEY = "directory_entries";
     private static final String SELECTED_DIRECTORY_KEY = "selected_directory";
     private static final int OPEN_DIRECTORY_REQUEST_CODE = 1;
@@ -63,6 +68,9 @@
     private TextView mNothingInDirectoryTextView;
     private TextView mPrimaryVolumeNameTextView;
     private Spinner mDirectoriesSpinner;
+    private LinearLayout mDirectoryAccessSettings;
+    private Button mLaunchDirectoryAccessSettings;
+
     private DirectoryEntryAdapter mAdapter;
     private ArrayList<DirectoryEntry> mDirectoryEntries;
 
@@ -102,12 +110,25 @@
     public void onViewCreated(final View rootView, Bundle savedInstanceState) {
         super.onViewCreated(rootView, savedInstanceState);
 
-        mCurrentDirectoryTextView = (TextView) rootView
-                .findViewById(R.id.textview_current_directory);
-        mNothingInDirectoryTextView = (TextView) rootView
-                .findViewById(R.id.textview_nothing_in_directory);
-        mPrimaryVolumeNameTextView = (TextView) rootView
-                .findViewById(R.id.textview_primary_volume_name);
+        mCurrentDirectoryTextView = rootView.findViewById(R.id.textview_current_directory);
+        mNothingInDirectoryTextView = rootView.findViewById(R.id.textview_nothing_in_directory);
+        mPrimaryVolumeNameTextView = rootView.findViewById(R.id.textview_primary_volume_name);
+
+        mDirectoryAccessSettings = rootView.findViewById(R.id.directory_access_settings);
+        mLaunchDirectoryAccessSettings = rootView.findViewById(R.id.launch);
+
+        // TODO: proper API check
+        if (Build.VERSION.CODENAME.equals("P")) {
+            mDirectoryAccessSettings.setVisibility(View.VISIBLE);
+            mLaunchDirectoryAccessSettings.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View view) {
+                    // TODO: use API constant for intent name
+                    Intent intent = new Intent("android.settings.DIRECTORY_ACCESS_SETTINGS");
+                    startActivity(intent);
+                }
+            });
+        }
 
         // Set onClickListener for the primary volume
         Button openPictureButton = (Button) rootView
@@ -117,6 +138,12 @@
             public void onClick(View view) {
                 String selected = mDirectoriesSpinner.getSelectedItem().toString();
                 String directoryName = getDirectoryName(selected);
+                Log.d(TAG, "Primary: selected=" + selected + " dir=" + directoryName);
+                if (directoryName == null) {
+                    Toast.makeText(getContext(), "Cannot select ROOT on primary directory",
+                            Toast.LENGTH_LONG).show();
+                    return;
+                }
                 StorageVolume storageVolume = mStorageManager.getPrimaryStorageVolume();
                 Intent intent = storageVolume.createAccessIntent(directoryName);
                 startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE);
@@ -139,7 +166,7 @@
             }
             LinearLayout volumeArea = (LinearLayout) mActivity.getLayoutInflater()
                     .inflate(R.layout.volume_entry, containerVolumes);
-            TextView volumeName = (TextView) volumeArea.findViewById(R.id.textview_volume_name);
+            final TextView volumeName = volumeArea.findViewById(R.id.textview_volume_name);
             volumeName.setText(volumeDescription);
             Button button = (Button) volumeArea.findViewById(R.id.button_open_directory);
             button.setOnClickListener(new View.OnClickListener() {
@@ -147,6 +174,8 @@
                 public void onClick(View view) {
                     String selected = mDirectoriesSpinner.getSelectedItem().toString();
                     String directoryName = getDirectoryName(selected);
+                    Log.d(TAG, "Secondary: volume=" + volumeName.getText() + ", selected=" + selected
+                            + ", dir=" + directoryName);
                     Intent intent = volume.createAccessIntent(directoryName);
                     startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE);
                 }
@@ -221,6 +250,8 @@
 
     private String getDirectoryName(String name) {
         switch (name) {
+            case "ROOT":
+                return null;
             case "ALARMS":
                 return Environment.DIRECTORY_ALARMS;
             case "DCIM":
diff --git a/content/documentsUi/ScopedDirectoryAccess/Application/src/main/res/layout/fragment_scoped_directory_access.xml b/content/documentsUi/ScopedDirectoryAccess/Application/src/main/res/layout/fragment_scoped_directory_access.xml
index dfee2aa..b2c6d1a 100644
--- a/content/documentsUi/ScopedDirectoryAccess/Application/src/main/res/layout/fragment_scoped_directory_access.xml
+++ b/content/documentsUi/ScopedDirectoryAccess/Application/src/main/res/layout/fragment_scoped_directory_access.xml
@@ -51,6 +51,24 @@
         </LinearLayout>
     </LinearLayout>
 
+    <LinearLayout
+        android:id="@+id/directory_access_settings"
+        android:visibility="gone"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layout_marginBottom="@dimen/margin_small">
+        <TextView
+            android:text="@string/directory_access_settings"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+        <Button
+            android:id="@+id/launch"
+            android:text="@string/launch"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+    </LinearLayout>
+
     <Spinner
         android:id="@+id/spinner_directories"
         android:layout_width="wrap_content"
diff --git a/content/documentsUi/ScopedDirectoryAccess/Application/src/main/res/values/strings.xml b/content/documentsUi/ScopedDirectoryAccess/Application/src/main/res/values/strings.xml
index 8c4edcd..9798da9 100644
--- a/content/documentsUi/ScopedDirectoryAccess/Application/src/main/res/values/strings.xml
+++ b/content/documentsUi/ScopedDirectoryAccess/Application/src/main/res/values/strings.xml
@@ -20,7 +20,10 @@
     <string name="selected_directory">Selected directory:\ </string>
     <string name="nothing_in_directory">Nothing in the directory</string>
     <string name="primary_volume_description">Internal shared storage</string>
+    <string name="launch">Launch</string>
+    <string name="directory_access_settings">Directory access settings</string>
     <string-array name="directories">
+        <item>ROOT</item>
         <item>ALARMS</item>
         <item>DCIM</item>
         <item>DOCUMENTS</item>
diff --git a/content/documentsUi/ScopedDirectoryAccess/gradle/wrapper/gradle-wrapper.properties b/content/documentsUi/ScopedDirectoryAccess/gradle/wrapper/gradle-wrapper.properties
index f36c9b8..6a5050a 100644
--- a/content/documentsUi/ScopedDirectoryAccess/gradle/wrapper/gradle-wrapper.properties
+++ b/content/documentsUi/ScopedDirectoryAccess/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/content/documentsUi/ScopedDirectoryAccess/template-params.xml b/content/documentsUi/ScopedDirectoryAccess/template-params.xml
index 4879b97..db7bcbc 100644
--- a/content/documentsUi/ScopedDirectoryAccess/template-params.xml
+++ b/content/documentsUi/ScopedDirectoryAccess/template-params.xml
@@ -22,12 +22,11 @@
     <package>com.example.android.scopeddirectoryaccess</package>
 
     <minSdk>24</minSdk>
-    <compileSdkVersion>24</compileSdkVersion>
+    <compileSdkVersion>27</compileSdkVersion>
     <targetSdkVersion>24</targetSdkVersion>
 
     <!-- Include additional dependencies here.-->
-    <dependency>com.android.support:recyclerview-v7:24.0.0</dependency>
-    <dependency>com.android.support:support-v4:24.0.0</dependency>
+    <dependency>com.android.support:recyclerview-v7:27.0.2</dependency>
 
     <template src="base" />
 
diff --git a/content/documentsUi/StorageClient/gradle/wrapper/gradle-wrapper.properties b/content/documentsUi/StorageClient/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/content/documentsUi/StorageClient/gradle/wrapper/gradle-wrapper.properties
+++ b/content/documentsUi/StorageClient/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/content/documentsUi/StorageProvider/gradle/wrapper/gradle-wrapper.properties b/content/documentsUi/StorageProvider/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/content/documentsUi/StorageProvider/gradle/wrapper/gradle-wrapper.properties
+++ b/content/documentsUi/StorageProvider/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/content/multiuser/AppRestrictions/gradle/wrapper/gradle-wrapper.properties b/content/multiuser/AppRestrictions/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/content/multiuser/AppRestrictions/gradle/wrapper/gradle-wrapper.properties
+++ b/content/multiuser/AppRestrictions/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/content/webview/PermissionRequest/gradle/wrapper/gradle-wrapper.properties b/content/webview/PermissionRequest/gradle/wrapper/gradle-wrapper.properties
index bac771b..a41d352 100644
--- a/content/webview/PermissionRequest/gradle/wrapper/gradle-wrapper.properties
+++ b/content/webview/PermissionRequest/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/experimental/markgoldstein/snippets1.java b/experimental/markgoldstein/snippets1.java
new file mode 100644
index 0000000..90b2f46
--- /dev/null
+++ b/experimental/markgoldstein/snippets1.java
@@ -0,0 +1,28 @@
+// These are some test snippets
+//
+// [START snip1]
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationManagerCompat;
+import android.support.v4.app.NotificationCompat.WearableExtender;
+// [END snip1]
+
+
+// [START snip2]
+int notificationId = 001;
+The channel ID of the notification.
+String id = "my_channel_01";
+// Build intent for notification content
+Intent viewIntent = new Intent(this, ViewEventActivity.class);
+viewIntent.putExtra(EXTRA_EVENT_ID, eventId);
+PendingIntent viewPendingIntent =
+        PendingIntent.getActivity(this, 0, viewIntent, 0);
+
+        // Notification channel ID is ignored for Android 7.1.1
+        // (API level 25) and lower.
+        NotificationCompat.Builder notificationBuilder =
+            new NotificationCompat.Builder(this, id)
+                    .setSmallIcon(R.drawable.ic_event)
+                            .setContentTitle(eventTitle)
+                                    .setContentText(eventLocation)
+                                           .setContentIntent(viewPendingIntent);
+// [END snip2]
diff --git a/experimental/ndkSampleGen/gradle/wrapper/gradle-wrapper.properties b/experimental/ndkSampleGen/gradle/wrapper/gradle-wrapper.properties
index 63d7276..577990e 100644
--- a/experimental/ndkSampleGen/gradle/wrapper/gradle-wrapper.properties
+++ b/experimental/ndkSampleGen/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/build.gradle b/input/autofill/AutofillFramework/Application/build.gradle
index 1dc66eb..50bbdc3 100644
--- a/input/autofill/AutofillFramework/Application/build.gradle
+++ b/input/autofill/AutofillFramework/Application/build.gradle
@@ -1,32 +1,17 @@
 apply plugin: 'com.android.application'
 
-dependencies {
-    compile "com.android.support:support-v4:26.0.1"
-    compile "com.android.support:support-v13:26.0.1"
-    compile "com.android.support:cardview-v7:26.0.1"
-    compile "com.android.support:appcompat-v7:26.0.1"
-    compile 'com.android.support:design:26.0.1'
-    compile 'com.android.support.constraint:constraint-layout:1.0.2'
-    compile group: 'com.google.code.gson', name: 'gson', version: '2.8.1'
-    compile group: 'com.google.guava', name: 'guava', version: '22.0-android'
-}
-
 // The sample build uses multiple directories to
 // keep boilerplate and common code separate from
 // the main sample code.
 List<String> dirs = [
-    'main']     // main sample code; look here for the interesting stuff.
+        'main']     // main sample code; look here for the interesting stuff.
 
 android {
-    compileSdkVersion 26
-    buildToolsVersion "26.0.1"
+    compileSdkVersion "android-P"
 
     defaultConfig {
         minSdkVersion 26
-        targetSdkVersion 26
-        jackOptions {
-            enabled true
-        }
+        targetSdkVersion 28
     }
 
     compileOptions {
@@ -44,4 +29,19 @@
         androidTest.setRoot('tests')
         androidTest.java.srcDirs = ['tests/src']
     }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+dependencies {
+    implementation "com.android.support:support-v4:28.0.0-alpha1"
+    implementation "com.android.support:support-v13:28.0.0-alpha1"
+    implementation "com.android.support:cardview-v7:28.0.0-alpha1"
+    implementation "com.android.support:appcompat-v7:28.0.0-alpha1"
+    implementation 'com.android.support:design:28.0.0-alpha1'
+    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
+    implementation group: 'com.google.guava', name: 'guava', version: '22.0-android'
 }
diff --git a/input/autofill/AutofillFramework/Application/src/main/AndroidManifest.xml b/input/autofill/AutofillFramework/Application/src/main/AndroidManifest.xml
index 7d075ab..a837128 100644
--- a/input/autofill/AutofillFramework/Application/src/main/AndroidManifest.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/AndroidManifest.xml
@@ -14,11 +14,11 @@
  limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.autofillframework"
+    package="com.example.android.autofill.app"
     android:versionCode="1"
     android:versionName="1.0">
 
-    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.INTERNET" />
 
     <application
         android:allowBackup="true"
@@ -27,84 +27,30 @@
         android:supportsRtl="true"
         android:theme="@style/Theme.AppCompat.Light">
         <activity
-            android:name=".app.MainActivity"
+            android:name="com.example.android.autofill.app.MainActivity"
             android:taskAffinity=".MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <activity android:name="com.example.android.autofill.app.commoncases.StandardSignInActivity" />
+        <activity android:name="com.example.android.autofill.app.commoncases.StandardAutoCompleteSignInActivity" />
+        <activity android:name="com.example.android.autofill.app.commoncases.VirtualSignInActivity" />
+        <activity android:name="com.example.android.autofill.app.WelcomeActivity" />
+        <activity android:name="com.example.android.autofill.app.edgecases.CreditCardActivity" />
+        <activity android:name="com.example.android.autofill.app.commoncases.CreditCardSpinnersActivity" />
+        <activity android:name="com.example.android.autofill.app.commoncases.EmailComposeActivity" />
+        <activity android:name="com.example.android.autofill.app.commoncases.CreditCardCompoundViewActivity" />
+        <activity android:name="com.example.android.autofill.app.commoncases.CreditCardDatePickerActivity" />
+        <activity android:name="com.example.android.autofill.app.edgecases.CreditCardAntiPatternActivity" />
         <activity
-            android:name=".app.StandardSignInActivity"
-            android:taskAffinity=".StandardSignInActivity" />
-        <activity
-            android:name=".app.StandardAutoCompleteSignInActivity"
-            android:taskAffinity=".StandardAutoCompleteSignInActivity" />
-        <activity
-            android:name=".app.VirtualSignInActivity"
-            android:taskAffinity=".VirtualSignInActivity" />
-        <activity android:name=".app.WelcomeActivity" />
-        <activity
-            android:name=".app.CreditCardActivity"
-            android:taskAffinity=".CreditCardActivity" />
-        <activity
-            android:name=".app.CreditCardSpinnersActivity"
-            android:taskAffinity=".CreditCardSpinnersActivity" />
-        <activity
-            android:name=".app.EmailComposeActivity"
-            android:taskAffinity=".EmailComposeActivity" />
-        <activity
-            android:name=".app.CreditCardCompoundViewActivity"
-            android:taskAffinity=".CreditCardCompoundViewActivity" />
-        <activity
-            android:name=".app.CreditCardDatePickerActivity"
-            android:taskAffinity=".CreditCardDatePickerActivity" />
-        <activity
-            android:name=".app.CreditCardAntiPatternActivity"
-            android:taskAffinity=".CreditCardAntiPatternActivity" />
-        <activity
-            android:name=".app.MultiplePartitionsActivity"
-            android:taskAffinity=".MultiplePartitionsActivity"
+            android:name="com.example.android.autofill.app.edgecases.MultiplePartitionsActivity"
             android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
-        <activity
-            android:name=".app.WebViewSignInActivity"
-            android:taskAffinity=".WebViewSignInActivity" />
-        <!--
-        Including launcher icon for Autofill Settings to convenience.
-        Not necessary for a real service.
-        -->
-        <activity
-            android:name=".multidatasetservice.settings.SettingsActivity"
-            android:exported="true"
-            android:label="@string/settings_name"
-            android:taskAffinity=".SettingsActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
+        <activity android:name="com.example.android.autofill.app.commoncases.WebViewSignInActivity" />
+        <activity android:name="com.example.android.autofill.app.edgecases.MultipleStepsSignInActivity" />
+        <activity android:name="com.example.android.autofill.app.edgecases.MultipleStepsCreditCardActivity" />
 
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-
-        <!--
-        Declare AutofillService implementation; only needed for a small number of apps that will
-        be implementing an AutofillService. Framework parses meta-data and sets the service's
-        Settings Activity based on what the meta-data resource points to.
-        -->
-        <service
-            android:name=".multidatasetservice.MyAutofillService"
-            android:label="Multi-Dataset Autofill Service"
-            android:permission="android.permission.BIND_AUTOFILL_SERVICE">
-            <meta-data
-                android:name="android.autofill"
-                android:resource="@xml/multidataset_service" />
-
-            <intent-filter>
-                <action android:name="android.service.autofill.AutofillService" />
-            </intent-filter>
-        </service>
-
-        <activity android:name=".multidatasetservice.AuthActivity" />
     </application>
 
 </manifest>
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/BaseMainFragment.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/BaseMainFragment.java
new file mode 100644
index 0000000..5be875c
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/BaseMainFragment.java
@@ -0,0 +1,24 @@
+/*
+ * 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 com.example.android.autofill.app;
+
+import android.support.annotation.StringRes;
+import android.support.v4.app.Fragment;
+
+public abstract class BaseMainFragment extends Fragment {
+    public abstract @StringRes int getPageTitleResId();
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/MainActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/MainActivity.java
new file mode 100644
index 0000000..2c8915b
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/MainActivity.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.example.android.autofill.app;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.design.widget.TabLayout;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.AppCompatActivity;
+
+import com.example.android.autofill.app.commoncases.CommonCasesFragment;
+import com.example.android.autofill.app.edgecases.EdgeCasesFragment;
+
+/**
+ * This is used to launch sample activities that showcase autofill.
+ */
+public class MainActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        ViewPager viewPager = findViewById(R.id.pager);
+        PagerAdapter pagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager(), this);
+        viewPager.setAdapter(pagerAdapter);
+        TabLayout tabLayout = findViewById(R.id.sliding_tabs);
+        tabLayout.setupWithViewPager(viewPager);
+    }
+
+    /**
+     * A simple pager adapter that holds 2 Fragments.
+     */
+    private static class ScreenSlidePagerAdapter extends FragmentPagerAdapter {
+        private BaseMainFragment[] fragments = new BaseMainFragment[]{new CommonCasesFragment(),
+                new EdgeCasesFragment()};
+
+        private Context mContext;
+
+        public ScreenSlidePagerAdapter(FragmentManager fm, Context context) {
+            super(fm);
+            mContext = context;
+        }
+
+        @Override
+        public Fragment getItem(int position) {
+            return fragments[position];
+        }
+
+        @Override
+        public int getCount() {
+            return fragments.length;
+        }
+
+        @Override
+        public CharSequence getPageTitle(int position) {
+            return mContext.getString(fragments[position].getPageTitleResId());
+        }
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/Util.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/Util.java
new file mode 100644
index 0000000..288a908
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/Util.java
@@ -0,0 +1,154 @@
+/*
+ * 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 com.example.android.autofill.app;
+
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
+import android.app.assist.AssistStructure.WindowNode;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewStructure.HtmlInfo;
+import android.view.autofill.AutofillValue;
+
+import java.util.Arrays;
+import java.util.Set;
+
+public final class Util {
+
+    public static final String TAG = "AutofillSample";
+    public static final boolean DEBUG = true;
+    public static final boolean VERBOSE = false;
+    public static final String EXTRA_DATASET_NAME = "dataset_name";
+    public static final String EXTRA_FOR_RESPONSE = "for_response";
+
+    private static void bundleToString(StringBuilder builder, Bundle data) {
+        final Set<String> keySet = data.keySet();
+        builder.append("[Bundle with ").append(keySet.size()).append(" keys:");
+        for (String key : keySet) {
+            builder.append(' ').append(key).append('=');
+            Object value = data.get(key);
+            if ((value instanceof Bundle)) {
+                bundleToString(builder, (Bundle) value);
+            } else {
+                builder.append((value instanceof Object[])
+                        ? Arrays.toString((Object[]) value) : value);
+            }
+        }
+        builder.append(']');
+    }
+
+    public static String bundleToString(Bundle data) {
+        if (data == null) {
+            return "N/A";
+        }
+        final StringBuilder builder = new StringBuilder();
+        bundleToString(builder, data);
+        return builder.toString();
+    }
+
+    public static String getAutofillTypeAsString(int type) {
+        switch (type) {
+            case View.AUTOFILL_TYPE_TEXT:
+                return "TYPE_TEXT";
+            case View.AUTOFILL_TYPE_LIST:
+                return "TYPE_LIST";
+            case View.AUTOFILL_TYPE_NONE:
+                return "TYPE_NONE";
+            case View.AUTOFILL_TYPE_TOGGLE:
+                return "TYPE_TOGGLE";
+            case View.AUTOFILL_TYPE_DATE:
+                return "TYPE_DATE";
+        }
+        return "UNKNOWN_TYPE";
+    }
+
+    private static String getAutofillValueAndTypeAsString(AutofillValue value) {
+        if (value == null) return "null";
+
+        StringBuilder builder = new StringBuilder(value.toString()).append('(');
+        if (value.isText()) {
+            builder.append("isText");
+        } else if (value.isDate()) {
+            builder.append("isDate");
+        } else if (value.isToggle()) {
+            builder.append("isToggle");
+        } else if (value.isList()) {
+            builder.append("isList");
+        }
+        return builder.append(')').toString();
+    }
+
+    public static void dumpStructure(AssistStructure structure) {
+        int nodeCount = structure.getWindowNodeCount();
+        Log.v(TAG, "dumpStructure(): component=" + structure.getActivityComponent()
+                + " numberNodes=" + nodeCount);
+        for (int i = 0; i < nodeCount; i++) {
+            Log.v(TAG, "node #" + i);
+            WindowNode node = structure.getWindowNodeAt(i);
+            dumpNode("  ", node.getRootViewNode());
+        }
+    }
+
+    private static void dumpNode(String prefix, ViewNode node) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(prefix)
+                .append("autoFillId: ").append(node.getAutofillId())
+                .append("\tidEntry: ").append(node.getIdEntry())
+                .append("\tid: ").append(node.getId())
+                .append("\tclassName: ").append(node.getClassName())
+                .append('\n');
+
+        builder.append(prefix)
+                .append("focused: ").append(node.isFocused())
+                .append("\tvisibility").append(node.getVisibility())
+                .append("\tchecked: ").append(node.isChecked())
+                .append("\twebDomain: ").append(node.getWebDomain())
+                .append("\thint: ").append(node.getHint())
+                .append('\n');
+
+        HtmlInfo htmlInfo = node.getHtmlInfo();
+
+        if (htmlInfo != null) {
+            builder.append(prefix)
+                    .append("HTML TAG: ").append(htmlInfo.getTag())
+                    .append(" attrs: ").append(htmlInfo.getAttributes())
+                    .append('\n');
+        }
+
+        String[] afHints = node.getAutofillHints();
+        CharSequence[] options = node.getAutofillOptions();
+        builder.append(prefix).append("afType: ").append(getAutofillTypeAsString(node.getAutofillType()))
+                .append("\tafValue:")
+                .append(getAutofillValueAndTypeAsString(node.getAutofillValue()))
+                .append("\tafOptions:").append(options == null ? "N/A" : Arrays.toString(options))
+                .append("\tafHints: ").append(afHints == null ? "N/A" : Arrays.toString(afHints))
+                .append("\tinputType:").append(node.getInputType())
+                .append('\n');
+
+        int numberChildren = node.getChildCount();
+        builder.append(prefix).append("# children: ").append(numberChildren)
+                .append("\ttext: ").append(node.getText())
+                .append('\n');
+
+        Log.v(TAG, builder.toString());
+        final String prefix2 = prefix + "  ";
+        for (int i = 0; i < numberChildren; i++) {
+            Log.v(TAG, prefix + "child #" + i);
+            dumpNode(prefix2, node.getChildAt(i));
+        }
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/WelcomeActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/WelcomeActivity.java
new file mode 100644
index 0000000..5f7b117
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/WelcomeActivity.java
@@ -0,0 +1,54 @@
+/*
+ * 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 com.example.android.autofill.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.TextView;
+
+import static java.lang.Math.toIntExact;
+
+public class WelcomeActivity extends AppCompatActivity {
+
+    public static Intent getStartActivityIntent(Context context) {
+        return new Intent(context, WelcomeActivity.class);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.welcome_activity);
+        final TextView countdownText = findViewById(R.id.countdownText);
+        new CountDownTimer(5000, 1000) {
+            @Override
+            public void onTick(long millisUntilFinished) {
+                int secondsRemaining = toIntExact(millisUntilFinished / 1000);
+                countdownText.setText(getResources().getQuantityString
+                        (R.plurals.welcome_page_countdown, secondsRemaining, secondsRemaining));
+            }
+
+            @Override
+            public void onFinish() {
+                if (!WelcomeActivity.this.isFinishing()) {
+                    finish();
+                }
+            }
+        }.start();
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CommonCasesFragment.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CommonCasesFragment.java
new file mode 100644
index 0000000..ebdb3fc
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CommonCasesFragment.java
@@ -0,0 +1,39 @@
+/*
+* 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 com.example.android.autofill.app.commoncases;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.example.android.autofill.app.BaseMainFragment;
+import com.example.android.autofill.app.R;
+
+public class CommonCasesFragment extends BaseMainFragment {
+    @Nullable
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.fragment_common_cases, container, false);
+    }
+
+    @Override
+    public int getPageTitleResId() {
+        return R.string.common_cases_page_title;
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardCompoundViewActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardCompoundViewActivity.java
new file mode 100644
index 0000000..b8df27d
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardCompoundViewActivity.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.example.android.autofill.app.commoncases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.EditText;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+import com.example.android.autofill.app.view.autofillable.CreditCardExpirationDateCompoundView;
+
+public class CreditCardCompoundViewActivity extends AppCompatActivity {
+
+    private CreditCardExpirationDateCompoundView mCcExpDateView;
+    private EditText mCcExpNumber;
+    private EditText mCcSecurityCode;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.credit_card_compound_view_activity);
+        mCcExpDateView = findViewById(R.id.creditCardExpirationView);
+        mCcExpNumber = findViewById(R.id.creditCardNumberField);
+        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
+        findViewById(R.id.submitButton).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                submit();
+            }
+        });
+        findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AutofillManager afm = getSystemService(AutofillManager.class);
+                if (afm != null) {
+                    afm.cancel();
+                }
+                resetFields();
+            }
+        });
+    }
+
+    private void resetFields() {
+        mCcExpDateView.reset();
+        mCcExpNumber.setText("");
+        mCcSecurityCode.setText("");
+    }
+
+    /**
+     * Launches new Activity and finishes, triggering an autofill save request if the user entered
+     * any new data.
+     */
+    private void submit() {
+        Intent intent = WelcomeActivity.getStartActivityIntent(this);
+        startActivity(intent);
+        finish();
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardDatePickerActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardDatePickerActivity.java
new file mode 100644
index 0000000..4a15886
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardDatePickerActivity.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.example.android.autofill.app.commoncases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.EditText;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+import com.example.android.autofill.app.view.autofillable.CreditCardExpirationDatePickerView;
+
+import static com.example.android.autofill.app.Util.TAG;
+
+public class CreditCardDatePickerActivity extends AppCompatActivity {
+
+    private CreditCardExpirationDatePickerView mCcExpDateView;
+    private EditText mCcExpNumber;
+    private EditText mCcSecurityCode;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.credit_card_date_picker_activity);
+        mCcExpDateView = findViewById(R.id.creditCardExpirationView);
+        mCcExpNumber = findViewById(R.id.creditCardNumberField);
+        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
+        findViewById(R.id.submitButton).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                submit();
+            }
+        });
+        findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AutofillManager afm = getSystemService(AutofillManager.class);
+                if (afm != null) {
+                    afm.cancel();
+                }
+                resetFields();
+            }
+        });
+
+        mCcExpDateView.reset();
+    }
+
+    private void resetFields() {
+        mCcExpDateView.reset();
+        mCcExpNumber.setText("");
+        mCcSecurityCode.setText("");
+    }
+
+    public void showDatePickerDialog(View v) {
+        if (v != mCcExpDateView) {
+            Log.w(TAG, "showDatePickerDialog() called on invalid view: " + v);
+            return;
+        }
+        mCcExpDateView.showDatePickerDialog(getSupportFragmentManager());
+    }
+
+
+    /**
+     * Launches new Activity and finishes, triggering an autofill save request if the user entered
+     * any new data.
+     */
+    private void submit() {
+        Intent intent = WelcomeActivity.getStartActivityIntent(this);
+        startActivity(intent);
+        finish();
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardSpinnersActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardSpinnersActivity.java
new file mode 100644
index 0000000..bab5379
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardSpinnersActivity.java
@@ -0,0 +1,123 @@
+/*
+ * 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 com.example.android.autofill.app.commoncases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+
+import java.util.Calendar;
+
+public class CreditCardSpinnersActivity extends AppCompatActivity {
+
+    private static final int CC_EXP_YEARS_COUNT = 5;
+
+    private final String[] years = new String[CC_EXP_YEARS_COUNT];
+
+    private Spinner mCcExpirationDaySpinner;
+    private Spinner mCcExpirationMonthSpinner;
+    private Spinner mCcExpirationYearSpinner;
+    private EditText mCcCardNumber;
+    private EditText mCcSecurityCode;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.credit_card_spinners_activity);
+        mCcExpirationDaySpinner = findViewById(R.id.expirationDay);
+        mCcExpirationMonthSpinner = findViewById(R.id.expirationMonth);
+        mCcExpirationYearSpinner = findViewById(R.id.expirationYear);
+        mCcCardNumber = findViewById(R.id.creditCardNumberField);
+        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
+
+        // Create an ArrayAdapter using the string array and a default spinner layout
+        ArrayAdapter<CharSequence> dayAdapter = ArrayAdapter.createFromResource
+                (this, R.array.day_array, android.R.layout.simple_spinner_item);
+        // Specify the layout to use when the list of choices appears
+        dayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        // Apply the adapter to the spinner
+        mCcExpirationDaySpinner.setAdapter(dayAdapter);
+
+        /*
+        R.array.month_array could be an array of Strings like "Jan", "Feb", "March", etc., and
+        the AutofillService would know how to autofill it. However, for the sake of keeping the
+        AutofillService simple, we will stick to a list of numbers (1, 2, ... 12) to represent
+        months; it makes it much easier to generate fake autofill data in the service that can still
+        autofill this spinner.
+        */
+        ArrayAdapter<CharSequence> monthAdapter = ArrayAdapter.createFromResource(
+                this, R.array.month_array, android.R.layout.simple_spinner_item);
+        // Adapter created from resource has getAutofillOptions() implemented by default.
+        monthAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mCcExpirationMonthSpinner.setAdapter(monthAdapter);
+
+        int year = Calendar.getInstance().get(Calendar.YEAR);
+        for (int i = 0; i < years.length; i++) {
+            years[i] = Integer.toString(year + i);
+        }
+        // Since the years Spinner uses a custom adapter, it needs to implement getAutofillOptions.
+        mCcExpirationYearSpinner.setAdapter(
+                new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, years) {
+                    @Override
+                    public CharSequence[] getAutofillOptions() {
+                        return years;
+                    }
+                });
+        findViewById(R.id.submit).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                submit();
+            }
+        });
+        findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AutofillManager afm = getSystemService(AutofillManager.class);
+                if (afm != null) {
+                    afm.cancel();
+                }
+                resetFields();
+            }
+        });
+    }
+
+    private void resetFields() {
+        mCcExpirationDaySpinner.setSelection(0);
+        mCcExpirationMonthSpinner.setSelection(0);
+        mCcExpirationYearSpinner.setSelection(0);
+        mCcCardNumber.setText("");
+        mCcSecurityCode.setText("");
+    }
+
+    /**
+     * Launches new Activity and finishes, triggering an autofill save request if the user entered
+     * any new data.
+     */
+    private void submit() {
+        Intent intent = WelcomeActivity.getStartActivityIntent(CreditCardSpinnersActivity.this);
+        startActivity(intent);
+        finish();
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/EmailComposeActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/EmailComposeActivity.java
new file mode 100644
index 0000000..94a0019
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/EmailComposeActivity.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.example.android.autofill.app.commoncases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+
+public class EmailComposeActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.email_compose_activity);
+        findViewById(R.id.sendButton).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                startActivity(WelcomeActivity.getStartActivityIntent(EmailComposeActivity.this));
+                finish();
+            }
+        });
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardAutoCompleteSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardAutoCompleteSignInActivity.java
new file mode 100644
index 0000000..089c6b2
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardAutoCompleteSignInActivity.java
@@ -0,0 +1,142 @@
+/*
+ * 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 com.example.android.autofill.app.commoncases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+
+import static com.example.android.autofill.app.Util.TAG;
+
+public class StandardAutoCompleteSignInActivity extends AppCompatActivity {
+    private AutoCompleteTextView mUsernameAutoCompleteField;
+    private TextView mPasswordField;
+    private TextView mLoginButton;
+    private TextView mClearButton;
+    private boolean mAutofillReceived = false;
+    private AutofillManager.AutofillCallback mAutofillCallback;
+    private AutofillManager mAutofillManager;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.login_with_autocomplete_activity);
+
+        mLoginButton = findViewById(R.id.login);
+        mClearButton = findViewById(R.id.clear);
+        mUsernameAutoCompleteField = findViewById(R.id.usernameField);
+        mPasswordField = findViewById(R.id.passwordField);
+        mLoginButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                login();
+            }
+        });
+        mClearButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AutofillManager afm = getSystemService(AutofillManager.class);
+                if (afm != null) {
+                    afm.cancel();
+                }
+                resetFields();
+            }
+        });
+        mAutofillCallback = new MyAutofillCallback();
+        mAutofillManager = getSystemService(AutofillManager.class);
+        ArrayAdapter<CharSequence> mockAutocompleteAdapter = ArrayAdapter.createFromResource
+                (this, R.array.mock_autocomplete_sign_in_suggestions,
+                        android.R.layout.simple_dropdown_item_1line);
+        mUsernameAutoCompleteField.setAdapter(mockAutocompleteAdapter);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mAutofillManager.registerCallback(mAutofillCallback);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mAutofillManager.unregisterCallback(mAutofillCallback);
+    }
+
+    private void resetFields() {
+        mUsernameAutoCompleteField.setText("");
+        mPasswordField.setText("");
+    }
+
+    /**
+     * Emulates a login action.
+     */
+    private void login() {
+        String username = mUsernameAutoCompleteField.getText().toString();
+        String password = mPasswordField.getText().toString();
+        boolean valid = isValidCredentials(username, password);
+        if (valid) {
+            Intent intent = WelcomeActivity.getStartActivityIntent(StandardAutoCompleteSignInActivity.this);
+            startActivity(intent);
+            finish();
+        } else {
+            Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show();
+        }
+    }
+
+    /**
+     * Dummy implementation for demo purposes. A real service should use secure mechanisms to
+     * authenticate users.
+     */
+    public boolean isValidCredentials(String username, String password) {
+        return username != null && password != null && username.equals(password);
+    }
+
+    private class MyAutofillCallback extends AutofillManager.AutofillCallback {
+        @Override
+        public void onAutofillEvent(@NonNull View view, int event) {
+            if (view instanceof AutoCompleteTextView) {
+                switch (event) {
+                    case AutofillManager.AutofillCallback.EVENT_INPUT_UNAVAILABLE:
+                        // no break on purpose
+                    case AutofillManager.AutofillCallback.EVENT_INPUT_HIDDEN:
+                        if (!mAutofillReceived) {
+                            ((AutoCompleteTextView) view).showDropDown();
+                        }
+                        break;
+                    case AutofillManager.AutofillCallback.EVENT_INPUT_SHOWN:
+                        mAutofillReceived = true;
+                        ((AutoCompleteTextView) view).setAdapter(null);
+                        break;
+                    default:
+                        Log.d(TAG, "Unexpected callback: " + event);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardSignInActivity.java
new file mode 100644
index 0000000..c333bce
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardSignInActivity.java
@@ -0,0 +1,88 @@
+/*
+ * 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 com.example.android.autofill.app.commoncases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+
+public class StandardSignInActivity extends AppCompatActivity {
+
+    private EditText mUsernameEditText;
+    private EditText mPasswordEditText;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.login_activity);
+        mUsernameEditText = findViewById(R.id.usernameField);
+        mPasswordEditText = findViewById(R.id.passwordField);
+        findViewById(R.id.login).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                login();
+            }
+        });
+        findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AutofillManager afm = getSystemService(AutofillManager.class);
+                if (afm != null) {
+                    afm.cancel();
+                }
+                resetFields();
+            }
+        });
+    }
+
+    private void resetFields() {
+        mUsernameEditText.setText("");
+        mPasswordEditText.setText("");
+    }
+
+    /**
+     * Emulates a login action.
+     */
+    private void login() {
+        String username = mUsernameEditText.getText().toString();
+        String password = mPasswordEditText.getText().toString();
+        boolean valid = isValidCredentials(username, password);
+        if (valid) {
+            Intent intent = WelcomeActivity.getStartActivityIntent(StandardSignInActivity.this);
+            startActivity(intent);
+            finish();
+        } else {
+            Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show();
+        }
+    }
+
+    /**
+     * Dummy implementation for demo purposes. A real service should use secure mechanisms to
+     * authenticate users.
+     */
+    public boolean isValidCredentials(String username, String password) {
+        return username != null && password != null && username.equalsIgnoreCase(password);
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/VirtualSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/VirtualSignInActivity.java
new file mode 100644
index 0000000..baafbf7
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/VirtualSignInActivity.java
@@ -0,0 +1,102 @@
+/*
+ * 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 com.example.android.autofill.app.commoncases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.Toast;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+import com.example.android.autofill.app.view.autofillable.CustomVirtualView;
+
+/**
+ * Activity that uses a virtual views for Username/Password text fields.
+ */
+public class VirtualSignInActivity extends AppCompatActivity {
+
+    private CustomVirtualView mCustomVirtualView;
+    private AutofillManager mAutofillManager;
+    private CustomVirtualView.Line mUsernameLine;
+    private CustomVirtualView.Line mPasswordLine;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.virtual_login_activity);
+
+        mCustomVirtualView = (CustomVirtualView) findViewById(R.id.custom_view);
+
+        CustomVirtualView.Partition credentialsPartition =
+                mCustomVirtualView.addPartition(getString(R.string.partition_credentials));
+        mUsernameLine = credentialsPartition.addLine("username", View.AUTOFILL_TYPE_TEXT,
+                getString(R.string.username_label),
+                "         ", false, View.AUTOFILL_HINT_USERNAME);
+        mPasswordLine = credentialsPartition.addLine("password", View.AUTOFILL_TYPE_TEXT,
+                getString(R.string.password_label),
+                "         ", true, View.AUTOFILL_HINT_PASSWORD);
+
+        findViewById(R.id.login).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                login();
+            }
+        });
+        findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                resetFields();
+                mAutofillManager.cancel();
+            }
+        });
+        mAutofillManager = getSystemService(AutofillManager.class);
+    }
+
+    private void resetFields() {
+        mUsernameLine.reset();
+        mPasswordLine.reset();
+        mCustomVirtualView.postInvalidate();
+    }
+
+    /**
+     * Emulates a login action.
+     */
+    private void login() {
+        String username = mUsernameLine.getText().toString();
+        String password = mPasswordLine.getText().toString();
+        boolean valid = isValidCredentials(username, password);
+        if (valid) {
+            Intent intent = WelcomeActivity.getStartActivityIntent(VirtualSignInActivity.this);
+            startActivity(intent);
+            finish();
+        } else {
+            Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show();
+        }
+    }
+
+    /**
+     * Dummy implementation for demo purposes. A real service should use secure mechanisms to
+     * authenticate users.
+     */
+    public boolean isValidCredentials(String username, String password) {
+        return username != null && password != null && username.equals(password);
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/WebViewSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/WebViewSignInActivity.java
new file mode 100644
index 0000000..9bd09f7
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/WebViewSignInActivity.java
@@ -0,0 +1,57 @@
+/*
+* 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 com.example.android.autofill.app.commoncases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import com.example.android.autofill.app.R;
+
+import static com.example.android.autofill.app.Util.DEBUG;
+import static com.example.android.autofill.app.Util.TAG;
+
+public class WebViewSignInActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.login_webview_activity);
+
+        WebView webView = findViewById(R.id.webview);
+        WebSettings webSettings = webView.getSettings();
+        webView.setWebViewClient(new WebViewClient());
+        webSettings.setJavaScriptEnabled(true);
+
+        String url = getIntent().getStringExtra("url");
+        if (url == null) {
+            url = "file:///android_res/raw/sample_form.html";
+        }
+        if (DEBUG) Log.d(TAG, "Clearing WebView data");
+        webView.clearHistory();
+        webView.clearFormData();
+        webView.clearCache(true);
+        Log.i(TAG, "Loading URL " + url);
+        webView.loadUrl(url);
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/AbstractMultipleStepsActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/AbstractMultipleStepsActivity.java
new file mode 100644
index 0000000..2baf335
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/AbstractMultipleStepsActivity.java
@@ -0,0 +1,174 @@
+/*
+ * 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 com.example.android.autofill.app.edgecases;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.example.android.autofill.app.R;
+
+import java.util.Map;
+
+import static com.example.android.autofill.app.Util.DEBUG;
+import static com.example.android.autofill.app.Util.TAG;
+
+/**
+ * Activity that emulates a multiple-steps wizard activity, where each step shows just one
+ * label and input.
+ * <p>
+ * <p>Its's useful to verify how an autofill service handles account creation that takes multiple
+ * steps.
+ */
+
+/*
+ * TODO list
+ * - use ConstraintLayout
+ * - use Fragments instead of replacing views directly
+ * - use custom view and/or layout xml for mSteps
+ */
+abstract class AbstractMultipleStepsActivity extends AppCompatActivity {
+
+    private TextView mStatus;
+    private ViewGroup mContainer;
+
+    private Button mPrev;
+    private Button mNext;
+    private Button mFinish;
+
+    private int mCurrentStep;
+    private boolean mFinished;
+
+    private LinearLayout[] mSteps;
+
+    /**
+     * Gets the mapping from resource id to autofill hints.
+     */
+    protected abstract Map<Integer, String> getStepsMap();
+
+    @Override
+    protected final void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.multiple_steps_activity);
+
+        mStatus = findViewById(R.id.status);
+        mContainer = findViewById(R.id.container);
+        mPrev = findViewById(R.id.prev);
+        mNext = findViewById(R.id.next);
+        mFinish = findViewById(R.id.finish);
+
+        View.OnClickListener onClickListener = (v) -> {
+            if (v == mPrev) {
+                showStep(mCurrentStep - 1);
+            } else if (v == mNext) {
+                showStep(mCurrentStep + 1);
+            } else {
+                finishIt();
+            }
+        };
+        mPrev.setOnClickListener(onClickListener);
+        mNext.setOnClickListener(onClickListener);
+        mFinish.setOnClickListener(onClickListener);
+
+        Map<Integer, String> stepsMap = getStepsMap();
+        if (DEBUG) debug("onCreate(): steps=%s", stepsMap);
+        initializeSteps(stepsMap);
+
+        showStep(0);
+    }
+
+    private void showStep(int i) {
+        if (mFinished || i < 0 || i >= mSteps.length) {
+            warn("Invalid step: %d (finished=%s, range=[%d,%d])",
+                    mFinished, i, 0, mSteps.length - 1);
+            return;
+        }
+        View step = mSteps[i];
+        mStatus.setText(getString(R.string.message_showing_step, i));
+        if (DEBUG) debug("Showing step %d", i);
+        if (mContainer.getChildCount() > 0) {
+            mContainer.removeViewAt(0);
+        }
+        mContainer.addView(step);
+        mCurrentStep = i;
+
+        mPrev.setEnabled(mCurrentStep != 0);
+        mNext.setEnabled(mCurrentStep != mSteps.length - 1);
+    }
+
+    private void updateButtons() {
+        mPrev.setEnabled(!mFinished && mCurrentStep != 0);
+        mNext.setEnabled(!mFinished && mCurrentStep != mSteps.length - 1);
+        mFinish.setEnabled(!mFinished);
+    }
+
+    private void finishIt() {
+        StringBuilder message = new StringBuilder(getString(R.string.message_finished))
+                .append("\n\n");
+        for (int i = 0; i < mSteps.length; i++) {
+            TextView label = (TextView) mSteps[i].getChildAt(0);
+            EditText input = (EditText) mSteps[i].getChildAt(1);
+            message.append(getString(R.string.message_step_description, label.getText(), input.getText()))
+                    .append('\n');
+        }
+        mStatus.setText(message.toString());
+        mContainer.removeAllViews();
+        mFinished = true;
+        updateButtons();
+    }
+
+    private void initializeSteps(Map<Integer, String> stepsMap) {
+        mSteps = new LinearLayout[stepsMap.size()];
+        int i = 0;
+        for (Map.Entry<Integer, String> entry : stepsMap.entrySet()) {
+            int labelId = entry.getKey();
+            String autofillHints = entry.getValue();
+            if (DEBUG) debug("step %d: %s->%s", i, getString(labelId), autofillHints);
+            mSteps[i++] = newStep(labelId, autofillHints);
+        }
+    }
+
+    private LinearLayout newStep(int labelId, String autofillHints) {
+        LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.HORIZONTAL);
+
+        TextView label = new TextView(this);
+        label.setText(labelId);
+        layout.addView(label);
+
+        EditText input = new EditText(this);
+        input.setAutofillHints(autofillHints);
+        input.setWidth(500); // TODO: proper size
+        layout.addView(input);
+
+        return layout;
+    }
+
+    protected void debug(String fmt, Object... args) {
+        Log.d(TAG, getLocalClassName() + "." + String.format(fmt, args));
+    }
+
+    protected void warn(String fmt, Object... args) {
+        Log.w(TAG, getLocalClassName() + "." + String.format(fmt, args));
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardActivity.java
new file mode 100644
index 0000000..3e68a01
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardActivity.java
@@ -0,0 +1,82 @@
+/*
+ * 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 com.example.android.autofill.app.edgecases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.EditText;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+
+public class CreditCardActivity extends AppCompatActivity {
+
+    private EditText mCcExpDayView;
+    private EditText mCcExpMonthView;
+    private EditText mCcExpYearView;
+    private EditText mCcNumber;
+    private EditText mCcSecurityCode;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.credit_card_activity);
+        mCcExpDayView = findViewById(R.id.expirationDay);
+        mCcExpMonthView = findViewById(R.id.expirationMonth);
+        mCcExpYearView = findViewById(R.id.expirationYear);
+        mCcNumber = findViewById(R.id.creditCardNumberField);
+        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
+        findViewById(R.id.submitButton).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                submit();
+            }
+        });
+        findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AutofillManager afm = getSystemService(AutofillManager.class);
+                if (afm != null) {
+                    afm.cancel();
+                }
+                resetFields();
+            }
+        });
+    }
+
+    private void resetFields() {
+        mCcExpDayView.setText("");
+        mCcExpMonthView.setText("");
+        mCcExpYearView.setText("");
+        mCcNumber.setText("");
+        mCcSecurityCode.setText("");
+    }
+
+    /**
+     * Launches new Activity and finishes, triggering an autofill save request if the user entered
+     * any new data.
+     */
+    private void submit() {
+        Intent intent = WelcomeActivity.getStartActivityIntent(this);
+        startActivity(intent);
+        finish();
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardAntiPatternActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardAntiPatternActivity.java
new file mode 100644
index 0000000..edffcc0
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardAntiPatternActivity.java
@@ -0,0 +1,76 @@
+/*
+ * 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 com.example.android.autofill.app.edgecases;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.EditText;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+
+public class CreditCardAntiPatternActivity extends AppCompatActivity {
+
+    private EditText mCcExpDateView;
+    private EditText mCcExpNumber;
+    private EditText mCcSecurityCode;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.credit_card_anti_pattern_activity);
+        mCcExpDateView = findViewById(R.id.creditCardExpirationView);
+        mCcExpNumber = findViewById(R.id.creditCardNumberField);
+        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
+        findViewById(R.id.submitButton).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                submit();
+            }
+        });
+        findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AutofillManager afm = getSystemService(AutofillManager.class);
+                if (afm != null) {
+                    afm.cancel();
+                }
+                resetFields();
+            }
+        });
+    }
+
+    private void resetFields() {
+        mCcExpDateView.setText("");
+        mCcExpNumber.setText("");
+        mCcSecurityCode.setText("");
+    }
+
+    /**
+     * Launches new Activity and finishes, triggering an autofill save request if the user entered
+     * any new data.
+     */
+    private void submit() {
+        Intent intent = WelcomeActivity.getStartActivityIntent(this);
+        startActivity(intent);
+        finish();
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/EdgeCasesFragment.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/EdgeCasesFragment.java
new file mode 100644
index 0000000..917be10
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/EdgeCasesFragment.java
@@ -0,0 +1,40 @@
+/*
+* 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 com.example.android.autofill.app.edgecases;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.example.android.autofill.app.BaseMainFragment;
+import com.example.android.autofill.app.R;
+
+public class EdgeCasesFragment extends BaseMainFragment {
+
+    @Nullable
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.fragment_edge_cases, container, false);
+    }
+
+    @Override
+    public int getPageTitleResId() {
+        return R.string.edge_cases_page_title;
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultiplePartitionsActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultiplePartitionsActivity.java
new file mode 100644
index 0000000..9e09b45
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultiplePartitionsActivity.java
@@ -0,0 +1,114 @@
+/*
+ * 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 com.example.android.autofill.app.edgecases;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.Toast;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.Util;
+import com.example.android.autofill.app.view.autofillable.CustomVirtualView;
+import com.example.android.autofill.app.view.autofillable.ScrollableCustomVirtualView;
+
+/**
+ * Activity used to demonstrated safe partitioning of data.
+ * <p>
+ * <p>It has multiple partitions, but only accepts autofill on each partition at time.
+ */
+/*
+ * TODO list
+ *
+ * - Fix top margin.
+ * - Use a combo box to select if credit card expiration date is expressed as date or text.
+ * - Use a dedicated TextView (instead of Toast) for error messages.
+ * - Use wrap_context to CustomView container.
+ * - Use different background color (or borders) for each partition.
+ * - Add more partitions (like address) - should match same partitions from service.
+ * - Add more hints (like w3c ones) - should match same hints from service.
+ */
+public class MultiplePartitionsActivity extends AppCompatActivity {
+
+    private ScrollableCustomVirtualView mCustomVirtualView;
+    private AutofillManager mAutofillManager;
+    private CustomVirtualView.Partition mCredentialsPartition;
+    private CustomVirtualView.Partition mCcPartition;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.multiple_partitions_activity);
+        mCustomVirtualView = findViewById(R.id.custom_view);
+        mCredentialsPartition =
+                mCustomVirtualView.addPartition(getString(R.string.partition_credentials));
+        mCredentialsPartition.addLine("username", View.AUTOFILL_TYPE_TEXT,
+                getString(R.string.username_label),
+                "         ", false, View.AUTOFILL_HINT_USERNAME);
+        mCredentialsPartition.addLine("password", View.AUTOFILL_TYPE_TEXT,
+                getString(R.string.password_label),
+                "         ", true, View.AUTOFILL_HINT_PASSWORD);
+        int ccExpirationType = View.AUTOFILL_TYPE_DATE;
+        // TODO: add a checkbox to switch between text / date instead
+        Intent intent = getIntent();
+        if (intent != null) {
+            int newType = intent.getIntExtra("dateType", -1);
+            if (newType != -1) {
+                ccExpirationType = newType;
+                String typeMessage = getString(R.string.message_credit_card_expiration_type,
+                        Util.getAutofillTypeAsString(ccExpirationType));
+                // TODO: display type in a header or proper status widget
+                Toast.makeText(getApplicationContext(), typeMessage, Toast.LENGTH_LONG).show();
+            }
+        }
+        mCcPartition = mCustomVirtualView.addPartition(getString(R.string.partition_credit_card));
+        mCcPartition.addLine("ccNumber", View.AUTOFILL_TYPE_TEXT,
+                getString(R.string.credit_card_number_label),
+                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_NUMBER);
+        mCcPartition.addLine("ccDay", View.AUTOFILL_TYPE_TEXT,
+                getString(R.string.credit_card_expiration_day_label),
+                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY);
+        mCcPartition.addLine("ccMonth", ccExpirationType,
+                getString(R.string.credit_card_expiration_month_label),
+                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH);
+        mCcPartition.addLine("ccYear", View.AUTOFILL_TYPE_TEXT,
+                getString(R.string.credit_card_expiration_year_label),
+                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR);
+        mCcPartition.addLine("ccDate", ccExpirationType,
+                getString(R.string.credit_card_expiration_date_label),
+                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE);
+        mCcPartition.addLine("ccSecurityCode", View.AUTOFILL_TYPE_TEXT,
+                getString(R.string.credit_card_security_code_label),
+                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE);
+        mAutofillManager = getSystemService(AutofillManager.class);
+        findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                resetFields();
+                mCustomVirtualView.resetPositions();
+                mAutofillManager.cancel();
+            }
+        });
+    }
+
+    private void resetFields() {
+        mCredentialsPartition.reset();
+        mCcPartition.reset();
+        mCustomVirtualView.postInvalidate();
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultipleStepsCreditCardActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultipleStepsCreditCardActivity.java
new file mode 100644
index 0000000..804b77f
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultipleStepsCreditCardActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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 com.example.android.autofill.app.edgecases;
+
+import android.view.View;
+
+import com.example.android.autofill.app.R;
+import com.google.common.collect.ImmutableMap;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class MultipleStepsCreditCardActivity extends AbstractMultipleStepsActivity {
+
+    @Override
+    protected Map<Integer, String> getStepsMap() {
+        LinkedHashMap<Integer, String> steps = new LinkedHashMap<>(4);
+        steps.put(R.string.credit_card_number_label,
+                View.AUTOFILL_HINT_CREDIT_CARD_NUMBER);
+        steps.put(R.string.credit_card_expiration_month_label,
+                View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH);
+        steps.put(R.string.credit_card_expiration_year_label,
+                View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR);
+        steps.put(R.string.credit_card_security_code_abbrev_label,
+                View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE);
+        return ImmutableMap.copyOf(steps);
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultipleStepsSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultipleStepsSignInActivity.java
new file mode 100644
index 0000000..ec45a9c
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultipleStepsSignInActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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 com.example.android.autofill.app.edgecases;
+
+import android.view.View;
+
+import com.example.android.autofill.app.R;
+import com.google.common.collect.ImmutableMap;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class MultipleStepsSignInActivity extends AbstractMultipleStepsActivity {
+
+    @Override
+    protected Map<Integer, String> getStepsMap() {
+        LinkedHashMap<Integer, String> steps = new LinkedHashMap<>(2);
+        steps.put(R.string.username_label, View.AUTOFILL_HINT_USERNAME);
+        steps.put(R.string.password_label, View.AUTOFILL_HINT_PASSWORD);
+        return ImmutableMap.copyOf(steps);
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/CreditCardExpirationDateCompoundView.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/CreditCardExpirationDateCompoundView.java
new file mode 100644
index 0000000..1cee75a
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/CreditCardExpirationDateCompoundView.java
@@ -0,0 +1,135 @@
+/*
+ * 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 com.example.android.autofill.app.view.autofillable;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillValue;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.FrameLayout;
+import android.widget.Spinner;
+
+import com.example.android.autofill.app.R;
+
+import java.util.Calendar;
+
+import static com.example.android.autofill.app.Util.TAG;
+
+/**
+ * A custom view that represents a {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} using
+ * 2 {@link Spinner spinners} to represent the credit card expiration month and year.
+ */
+public class CreditCardExpirationDateCompoundView extends FrameLayout {
+
+    private static final int CC_EXP_YEARS_COUNT = 5;
+
+    private final String[] mYears = new String[CC_EXP_YEARS_COUNT];
+
+    private Spinner mCcExpMonthSpinner;
+    private Spinner mCcExpYearSpinner;
+
+    public CreditCardExpirationDateCompoundView(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public CreditCardExpirationDateCompoundView(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public CreditCardExpirationDateCompoundView(@NonNull Context context,
+            @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public CreditCardExpirationDateCompoundView(@NonNull final Context context,
+            @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        View rootView = LayoutInflater.from(context).inflate(R.layout.cc_exp_date, this);
+        mCcExpMonthSpinner = rootView.findViewById(R.id.ccExpMonth);
+        mCcExpYearSpinner = rootView.findViewById(R.id.ccExpYear);
+        setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS);
+        ArrayAdapter<CharSequence> monthAdapter = ArrayAdapter.createFromResource
+                (context, R.array.month_array, android.R.layout.simple_spinner_item);
+        monthAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mCcExpMonthSpinner.setAdapter(monthAdapter);
+        int year = Calendar.getInstance().get(Calendar.YEAR);
+        for (int i = 0; i < mYears.length; i++) {
+            mYears[i] = Integer.toString(year + i);
+        }
+        mCcExpYearSpinner.setAdapter(new ArrayAdapter<>(context,
+                android.R.layout.simple_spinner_item, mYears));
+        AdapterView.OnItemSelectedListener onItemSelectedListener =
+                new AdapterView.OnItemSelectedListener() {
+                    @Override
+                    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                        context.getSystemService(AutofillManager.class)
+                                .notifyValueChanged(CreditCardExpirationDateCompoundView.this);
+                    }
+
+                    @Override
+                    public void onNothingSelected(AdapterView<?> parent) {
+                    }
+                };
+        mCcExpMonthSpinner.setOnItemSelectedListener(onItemSelectedListener);
+        mCcExpYearSpinner.setOnItemSelectedListener(onItemSelectedListener);
+    }
+
+    @Override
+    public AutofillValue getAutofillValue() {
+        Calendar calendar = Calendar.getInstance();
+        // Set hours, minutes, seconds, and millis to 0 to ensure getAutofillValue() == the value
+        // set by autofill(). Without this line, the view will not turn yellow when updated.
+        calendar.clear();
+        int year = Integer.parseInt(mCcExpYearSpinner.getSelectedItem().toString());
+        int month = mCcExpMonthSpinner.getSelectedItemPosition();
+        calendar.set(Calendar.YEAR, year);
+        calendar.set(Calendar.MONTH, month);
+        long unixTime = calendar.getTimeInMillis();
+        return AutofillValue.forDate(unixTime);
+    }
+
+    @Override
+    public void autofill(AutofillValue value) {
+        if (!value.isDate()) {
+            Log.w(TAG, "Ignoring autofill() because service sent a non-date value:" + value);
+            return;
+        }
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(value.getDateValue());
+        int month = calendar.get(Calendar.MONTH);
+        int year = calendar.get(Calendar.YEAR);
+        mCcExpMonthSpinner.setSelection(month);
+        mCcExpYearSpinner.setSelection(year - Integer.parseInt(mYears[0]));
+    }
+
+    @Override
+    public int getAutofillType() {
+        return AUTOFILL_TYPE_DATE;
+    }
+
+    public void reset() {
+        mCcExpMonthSpinner.setSelection(0);
+        mCcExpYearSpinner.setSelection(0);
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/CreditCardExpirationDatePickerView.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/CreditCardExpirationDatePickerView.java
new file mode 100644
index 0000000..870825a
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/CreditCardExpirationDatePickerView.java
@@ -0,0 +1,163 @@
+/*
+ * 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 com.example.android.autofill.app.view.autofillable;
+
+import android.app.DatePickerDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v7.widget.AppCompatEditText;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.autofill.AutofillValue;
+import android.widget.DatePicker;
+
+import com.example.android.autofill.app.R;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import static com.example.android.autofill.app.Util.DEBUG;
+import static com.example.android.autofill.app.Util.TAG;
+
+/**
+ * A custom view that represents a {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} using
+ * a non-editable {@link EditText} that triggers a {@link DatePickerDialog} to represent the
+ * credit card expiration month and year.
+ */
+public class CreditCardExpirationDatePickerView extends AppCompatEditText {
+
+    private static final int CC_EXP_YEARS_COUNT = 5;
+
+    /**
+     * Calendar instance used for month / year calculations. Should be reset before each use.
+     */
+    private final Calendar mTempCalendar;
+
+    private int mMonth;
+    private int mYear;
+
+    public CreditCardExpirationDatePickerView(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public CreditCardExpirationDatePickerView(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public CreditCardExpirationDatePickerView(@NonNull Context context,
+            @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        // Use the current date as the initial date in the picker.
+        mTempCalendar = Calendar.getInstance();
+        mYear = mTempCalendar.get(Calendar.YEAR);
+        mMonth = mTempCalendar.get(Calendar.MONTH);
+    }
+
+    /**
+     * Gets a temporary calendar set with the View's year and month.
+     */
+    private Calendar getCalendar() {
+        mTempCalendar.clear();
+        mTempCalendar.set(Calendar.YEAR, mYear);
+        mTempCalendar.set(Calendar.MONTH, mMonth);
+        mTempCalendar.set(Calendar.DATE, 1);
+        return mTempCalendar;
+    }
+
+    @Override
+    public AutofillValue getAutofillValue() {
+        Calendar c = getCalendar();
+        AutofillValue value = AutofillValue.forDate(c.getTimeInMillis());
+        if (DEBUG) Log.d(TAG, "getAutofillValue(): " + value);
+        return value;
+    }
+
+    @Override
+    public void autofill(AutofillValue value) {
+        if (value == null || !value.isDate()) {
+            Log.w(TAG, "autofill(): invalid value " + value);
+            return;
+        }
+        long time = value.getDateValue();
+        mTempCalendar.setTimeInMillis(time);
+        int year = mTempCalendar.get(Calendar.YEAR);
+        int month = mTempCalendar.get(Calendar.MONTH);
+        if (DEBUG) Log.d(TAG, "autofill(" + value + "): " + month + "/" + year);
+        setDate(year, month);
+    }
+
+    private void setDate(int year, int month) {
+        mYear = year;
+        mMonth = month;
+        Date selectedDate = new Date(getCalendar().getTimeInMillis());
+        String dateString = DateFormat.getDateFormat(getContext()).format(selectedDate);
+        setText(dateString);
+    }
+
+    @Override
+    public int getAutofillType() {
+        return AUTOFILL_TYPE_DATE;
+    }
+
+    public void reset() {
+        mTempCalendar.setTimeInMillis(System.currentTimeMillis());
+        setDate(mTempCalendar.get(Calendar.YEAR), mTempCalendar.get(Calendar.MONTH));
+    }
+
+    public void showDatePickerDialog(FragmentManager fragmentManager) {
+        DatePickerFragment newFragment = new DatePickerFragment();
+        newFragment.mParent = this;
+        newFragment.show(fragmentManager, "datePicker");
+    }
+
+    public static class DatePickerFragment extends DialogFragment
+            implements DatePickerDialog.OnDateSetListener {
+
+        private CreditCardExpirationDatePickerView mParent;
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            DatePickerDialog dialog = new DatePickerDialog(getActivity(),
+                    R.style.CustomDatePickerDialogTheme, this, mParent.mYear, mParent.mMonth, 1);
+
+            DatePicker datePicker = dialog.getDatePicker();
+
+            // Limit range.
+            Calendar c = mParent.getCalendar();
+            datePicker.setMinDate(c.getTimeInMillis());
+            c.set(Calendar.YEAR, mParent.mYear + CC_EXP_YEARS_COUNT - 1);
+            datePicker.setMaxDate(c.getTimeInMillis());
+
+            // Remove day.
+            datePicker.findViewById(getResources().getIdentifier("day", "id", "android"))
+                    .setVisibility(View.GONE);
+            return dialog;
+        }
+
+        @Override
+        public void onDateSet(DatePicker view, int year, int month, int day) {
+            mParent.setDate(year, month);
+        }
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/CustomVirtualView.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/CustomVirtualView.java
new file mode 100644
index 0000000..6c6e125
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/CustomVirtualView.java
@@ -0,0 +1,508 @@
+/*
+ * 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 com.example.android.autofill.app.view.autofillable;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Rect;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewStructure;
+import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillValue;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.Util;
+import com.google.common.base.Preconditions;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+
+import static com.example.android.autofill.app.Util.bundleToString;
+
+/**
+ * A custom View with a virtual structure for fields supporting {@link View#getAutofillHints()}
+ */
+public class CustomVirtualView extends View {
+
+    protected static final boolean DEBUG = true;
+    protected static final boolean VERBOSE = false;
+
+    /**
+     * When set, it notifies AutofillManager of focus change as the view scrolls, so the
+     * autofill UI is continually drawn.
+     * <p>
+     * <p>This is janky and incompatible with the way the autofill UI works on native views, but
+     * it's a cool experiment!
+     */
+    private static final boolean DRAW_AUTOFILL_UI_AFTER_SCROLL = false;
+
+    private static final String TAG = "CustomView";
+    private static final int DEFAULT_TEXT_HEIGHT_DP = 34;
+    private static final int VERTICAL_GAP = 10;
+    private static final int UNFOCUSED_COLOR = Color.BLACK;
+    private static final int FOCUSED_COLOR = Color.RED;
+    private static int sNextId;
+    protected final AutofillManager mAutofillManager;
+    private final ArrayList<Line> mVirtualViewGroups = new ArrayList<>();
+    private final SparseArray<Item> mVirtualViews = new SparseArray<>();
+    private final SparseArray<Partition> mPartitionsByAutofillId = new SparseArray<>();
+    private final ArrayMap<String, Partition> mPartitionsByName = new ArrayMap<>();
+    protected Line mFocusedLine;
+    protected int mTopMargin;
+    protected int mLeftMargin;
+    private Paint mTextPaint;
+    private int mTextHeight;
+    private int mLineLength;
+
+    public CustomVirtualView(Context context) {
+        this(context, null);
+    }
+
+    public CustomVirtualView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public CustomVirtualView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public CustomVirtualView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mAutofillManager = context.getSystemService(AutofillManager.class);
+        mTextPaint = new Paint();
+        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomVirtualView,
+                defStyleAttr, defStyleRes);
+        int defaultHeight =
+                (int) (DEFAULT_TEXT_HEIGHT_DP * getResources().getDisplayMetrics().density);
+        mTextHeight = typedArray.getDimensionPixelSize(
+                R.styleable.CustomVirtualView_internalTextSize, defaultHeight);
+        typedArray.recycle();
+        resetCoordinates();
+    }
+
+    protected void resetCoordinates() {
+        mTextPaint.setStyle(Style.FILL);
+        mTextPaint.setTextSize(mTextHeight);
+        mTopMargin = getPaddingTop();
+        mLeftMargin = getPaddingStart();
+        mLineLength = mTextHeight + VERTICAL_GAP;
+    }
+
+    @Override
+    public void autofill(SparseArray<AutofillValue> values) {
+        Context context = getContext();
+
+        // User has just selected a Dataset from the list of autofill suggestions.
+        // The Dataset is comprised of a list of AutofillValues, with each AutofillValue meant
+        // to fill a specific autofillable view. Now we have to update the UI based on the
+        // AutofillValues in the list, but first we make sure all autofilled values belong to the
+        // same partition
+        if (DEBUG) Log.d(TAG, "autofill(): " + values);
+
+        // First get the name of all partitions in the values
+        ArraySet<String> partitions = new ArraySet<>();
+        for (int i = 0; i < values.size(); i++) {
+            int id = values.keyAt(i);
+            Partition partition = mPartitionsByAutofillId.get(id);
+            if (partition == null) {
+                showError(context.getString(R.string.message_autofill_no_partitions, id,
+                        mPartitionsByAutofillId));
+                return;
+            }
+            partitions.add(partition.mName);
+        }
+
+        // Then make sure they follow the Highlander rule (There can be only one)
+        if (partitions.size() != 1) {
+            showError(context.getString(R.string.message_autofill_blocked, partitions));
+            return;
+        }
+
+        // Finally, autofill it.
+        DateFormat df = android.text.format.DateFormat.getDateFormat(context);
+        for (int i = 0; i < values.size(); i++) {
+            int id = values.keyAt(i);
+            AutofillValue value = values.valueAt(i);
+            Item item = mVirtualViews.get(id);
+
+            if (item == null) {
+                Log.w(TAG, "No item for id " + id);
+                continue;
+            }
+
+            if (!item.editable) {
+                showError(context.getString(R.string.message_autofill_readonly, item.text));
+                continue;
+            }
+
+            // Check if the type was properly set by the autofill service
+            if (DEBUG) {
+                Log.d(TAG, "Validating " + i
+                        + ": expectedType=" + Util.getAutofillTypeAsString(item.type)
+                        + "(" + item.type + "), value=" + value);
+            }
+            boolean valid = false;
+            if (value.isText() && item.type == AUTOFILL_TYPE_TEXT) {
+                item.text = value.getTextValue();
+                valid = true;
+            } else if (value.isDate() && item.type == AUTOFILL_TYPE_DATE) {
+                item.text = df.format(new Date(value.getDateValue()));
+                valid = true;
+            } else {
+                Log.w(TAG, "Unsupported type: " + value);
+            }
+            if (!valid) {
+                item.text = context.getString(R.string.message_autofill_invalid);
+            }
+        }
+        postInvalidate();
+        showMessage(context.getString(R.string.message_autofill_ok, partitions.valueAt(0)));
+    }
+
+    @Override
+    public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
+        // Build a ViewStructure that will get passed to the AutofillService by the framework
+        // when it is time to find autofill suggestions.
+        structure.setClassName(getClass().getName());
+        int childrenSize = mVirtualViews.size();
+        if (DEBUG) {
+            Log.d(TAG, "onProvideAutofillVirtualStructure(): flags = " + flags + ", items = "
+                    + childrenSize + ", extras: " + bundleToString(structure.getExtras()));
+        }
+        int index = structure.addChildCount(childrenSize);
+        // Traverse through the view hierarchy, including virtual child views. For each view, we
+        // need to set the relevant autofill metadata and add it to the ViewStructure.
+        for (int i = 0; i < childrenSize; i++) {
+            Item item = mVirtualViews.valueAt(i);
+            if (DEBUG) Log.d(TAG, "Adding new child at index " + index + ": " + item);
+            ViewStructure child = structure.newChild(index);
+            child.setAutofillId(structure.getAutofillId(), item.id);
+            child.setAutofillHints(item.hints);
+            child.setAutofillType(item.type);
+            child.setAutofillValue(item.getAutofillValue());
+            child.setDataIsSensitive(!item.sanitized);
+            child.setFocused(item.focused);
+            child.setVisibility(View.VISIBLE);
+            child.setDimens(item.line.mBounds.left, item.line.mBounds.top, 0, 0,
+                    item.line.mBounds.width(), item.line.mBounds.height());
+            child.setId(item.id, getContext().getPackageName(), null, item.idEntry);
+            child.setClassName(item.getClassName());
+            child.setDimens(item.line.mBounds.left, item.line.mBounds.top, 0, 0,
+                    item.line.mBounds.width(), item.line.mBounds.height());
+            index++;
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        if (VERBOSE) {
+            Log.v(TAG, "onDraw(): " + mVirtualViewGroups.size() + " lines; canvas:" + canvas);
+        }
+        float x;
+        float y = mTopMargin + mLineLength;
+        for (int i = 0; i < mVirtualViewGroups.size(); i++) {
+            Line line = mVirtualViewGroups.get(i);
+            x = mLeftMargin;
+            if (VERBOSE) Log.v(TAG, "Drawing '" + line + "' at " + x + "x" + y);
+            mTextPaint.setColor(line.mFieldTextItem.focused ? FOCUSED_COLOR : UNFOCUSED_COLOR);
+            String readOnlyText = line.mLabelItem.text + ":  [";
+            String writeText = line.mFieldTextItem.text + "]";
+            // Paints the label first...
+            canvas.drawText(readOnlyText, x, y, mTextPaint);
+            // ...then paints the edit text and sets the proper boundary
+            float deltaX = mTextPaint.measureText(readOnlyText);
+            x += deltaX;
+            line.mBounds.set((int) x, (int) (y - mLineLength),
+                    (int) (x + mTextPaint.measureText(writeText)), (int) y);
+            if (VERBOSE) Log.v(TAG, "setBounds(" + x + ", " + y + "): " + line.mBounds);
+            canvas.drawText(writeText, x, y, mTextPaint);
+            y += mLineLength;
+
+            if (DRAW_AUTOFILL_UI_AFTER_SCROLL) {
+                line.notifyFocusChanged();
+            }
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        int y = (int) event.getY();
+        onMotion(y);
+        return super.onTouchEvent(event);
+    }
+
+    /**
+     * Handles a motion event.
+     *
+     * @param y y coordinate.
+     */
+    protected void onMotion(int y) {
+        if (DEBUG) {
+            Log.d(TAG, "onMotion(): y=" + y + ", range=" + mLineLength + ", top=" + mTopMargin);
+        }
+        int lowerY = mTopMargin;
+        int upperY = -1;
+        for (int i = 0; i < mVirtualViewGroups.size(); i++) {
+            Line line = mVirtualViewGroups.get(i);
+            upperY = lowerY + mLineLength;
+            if (DEBUG) Log.d(TAG, "Line " + i + " ranges from " + lowerY + " to " + upperY);
+            if (lowerY <= y && y <= upperY) {
+                if (mFocusedLine != null) {
+                    Log.d(TAG, "Removing focus from " + mFocusedLine);
+                    mFocusedLine.changeFocus(false);
+                }
+                Log.d(TAG, "Changing focus to " + line);
+                mFocusedLine = line;
+                mFocusedLine.changeFocus(true);
+                invalidate();
+                break;
+            }
+            lowerY += mLineLength;
+        }
+    }
+
+    /**
+     * Creates a new partition with the given name.
+     *
+     * @throws IllegalArgumentException if such partition already exists.
+     */
+    public Partition addPartition(String name) {
+        Preconditions.checkNotNull(name, "Name cannot be null.");
+        Preconditions.checkArgument(!mPartitionsByName.containsKey(name),
+                "Partition with such name already exists.");
+        Partition partition = new Partition(name);
+        mPartitionsByName.put(name, partition);
+        return partition;
+    }
+
+    private void showError(String message) {
+        showMessage(true, message);
+    }
+
+    private void showMessage(String message) {
+        showMessage(false, message);
+    }
+
+    private void showMessage(boolean warning, String message) {
+        if (warning) {
+            Log.w(TAG, message);
+        } else {
+            Log.i(TAG, message);
+        }
+        Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
+    }
+
+
+    protected static final class Item {
+        protected final int id;
+        private final String idEntry;
+        private final Line line;
+        private final boolean editable;
+        private final boolean sanitized;
+        private final String[] hints;
+        private final int type;
+        private CharSequence text;
+        private boolean focused = false;
+        private long date;
+
+        Item(Line line, int id, String idEntry, String[] hints, int type, CharSequence text,
+                boolean editable, boolean sanitized) {
+            this.line = line;
+            this.id = id;
+            this.idEntry = idEntry;
+            this.text = text;
+            this.editable = editable;
+            this.sanitized = sanitized;
+            this.hints = hints;
+            this.type = type;
+        }
+
+        @Override
+        public String toString() {
+            return id + "/" + idEntry + ": "
+                    + (type == AUTOFILL_TYPE_DATE ? date : text) // TODO: use DateFormat for date
+                    + " (" + Util.getAutofillTypeAsString(type) + ")"
+                    + (editable ? " (editable)" : " (read-only)"
+                    + (sanitized ? " (sanitized)" : " (sensitive"))
+                    + (hints == null ? " (no hints)" : " ( " + Arrays.toString(hints) + ")");
+        }
+
+        public String getClassName() {
+            return editable ? EditText.class.getName() : TextView.class.getName();
+        }
+
+        public AutofillValue getAutofillValue() {
+            switch (type) {
+                case AUTOFILL_TYPE_TEXT:
+                    return (TextUtils.getTrimmedLength(text) > 0)
+                            ? AutofillValue.forText(text)
+                            : null;
+                case AUTOFILL_TYPE_DATE:
+                    return AutofillValue.forDate(date);
+                default:
+                    return null;
+            }
+        }
+    }
+
+    /**
+     * A partition represents a logical group of items, such as credit card info.
+     */
+    public final class Partition {
+        private final String mName;
+        private final SparseArray<Line> mLines = new SparseArray<>();
+
+        private Partition(String name) {
+            mName = name;
+        }
+
+        /**
+         * Adds a new line (containining a label and an input field) to the view.
+         *
+         * @param idEntryPrefix id prefix used to identify the line - label node will be suffixed
+         *                      with {@code Label} and editable node with {@code Field}.
+         * @param autofillType  {@link View#getAutofillType() autofill type} of the field.
+         * @param label         text used in the label.
+         * @param text          initial text used in the input field.
+         * @param sensitive     whether the input is considered sensitive.
+         * @param autofillHints list of autofill hints.
+         * @return the new line.
+         */
+        public Line addLine(String idEntryPrefix, int autofillType, String label, String text,
+                boolean sensitive, String... autofillHints) {
+            Preconditions.checkArgument(autofillType == AUTOFILL_TYPE_TEXT ||
+                    autofillType == AUTOFILL_TYPE_DATE, "Unsupported type: " + autofillType);
+            Line line = new Line(idEntryPrefix, autofillType, label, autofillHints, text,
+                    !sensitive);
+            mVirtualViewGroups.add(line);
+            int id = line.mFieldTextItem.id;
+            mLines.put(id, line);
+            mVirtualViews.put(line.mLabelItem.id, line.mLabelItem);
+            mVirtualViews.put(id, line.mFieldTextItem);
+            mPartitionsByAutofillId.put(id, this);
+
+            return line;
+        }
+
+        /**
+         * Resets the value of all items in the partition.
+         */
+        public void reset() {
+            for (int i = 0; i < mLines.size(); i++) {
+                mLines.valueAt(i).reset();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return mName;
+        }
+    }
+
+    /**
+     * A line in the virtual view contains a label and an input field.
+     */
+    public final class Line {
+
+        protected final Item mFieldTextItem;
+        // Boundaries of the text field, relative to the CustomView
+        private final Rect mBounds = new Rect();
+        private final Item mLabelItem;
+        private final int mAutofillType;
+
+        private Line(String idEntryPrefix, int autofillType, String label, String[] hints,
+                String text, boolean sanitized) {
+            this.mAutofillType = autofillType;
+            this.mLabelItem = new Item(this, ++sNextId, idEntryPrefix + "Label", null,
+                    AUTOFILL_TYPE_NONE, label, false, true);
+            this.mFieldTextItem = new Item(this, ++sNextId, idEntryPrefix + "Field", hints,
+                    autofillType, text, true, sanitized);
+        }
+
+        private void changeFocus(boolean focused) {
+            mFieldTextItem.focused = focused;
+            notifyFocusChanged();
+        }
+
+        void notifyFocusChanged() {
+            if (mFieldTextItem.focused) {
+                Rect absBounds = getAbsCoordinates();
+                if (DEBUG) {
+                    Log.d(TAG, "focus gained on " + mFieldTextItem.id + "; absBounds=" + absBounds);
+                }
+                mAutofillManager.notifyViewEntered(CustomVirtualView.this, mFieldTextItem.id,
+                        absBounds);
+            } else {
+                if (DEBUG) Log.d(TAG, "focus lost on " + mFieldTextItem.id);
+                mAutofillManager.notifyViewExited(CustomVirtualView.this, mFieldTextItem.id);
+            }
+        }
+
+        private Rect getAbsCoordinates() {
+            // Must offset the boundaries so they're relative to the CustomView.
+            int offset[] = new int[2];
+            getLocationOnScreen(offset);
+            Rect absBounds = new Rect(mBounds.left + offset[0],
+                    mBounds.top + offset[1],
+                    mBounds.right + offset[0], mBounds.bottom + offset[1]);
+            if (VERBOSE) {
+                Log.v(TAG, "getAbsCoordinates() for " + mFieldTextItem.id + ": bounds=" + mBounds
+                        + " offset: " + Arrays.toString(offset) + " absBounds: " + absBounds);
+            }
+            return absBounds;
+        }
+
+        /**
+         * Gets the value of the input field text.
+         */
+        public CharSequence getText() {
+            return mFieldTextItem.text;
+        }
+
+        /**
+         * Resets the value of the input field text.
+         */
+        public void reset() {
+            mFieldTextItem.text = "        ";
+        }
+
+        @Override
+        public String toString() {
+            return "Label: " + mLabelItem + " Text: " + mFieldTextItem + " Focused: " +
+                    mFieldTextItem.focused + " Type: " + mAutofillType;
+        }
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/ScrollableCustomVirtualView.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/ScrollableCustomVirtualView.java
new file mode 100644
index 0000000..cdc9d98
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/autofillable/ScrollableCustomVirtualView.java
@@ -0,0 +1,105 @@
+/*
+ * 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 com.example.android.autofill.app.view.autofillable;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+
+/**
+ * A version of {@link CustomVirtualView} that uses gesture to provide scrolling.
+ */
+public class ScrollableCustomVirtualView extends CustomVirtualView
+        implements GestureDetector.OnGestureListener {
+
+    private static final String TAG = "ScrollableCustomView";
+
+    private GestureDetector mGestureDetector;
+
+    public ScrollableCustomVirtualView(Context context) {
+        this(context, null);
+    }
+
+    public ScrollableCustomVirtualView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+
+    }
+
+    public ScrollableCustomVirtualView(Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public ScrollableCustomVirtualView(Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mGestureDetector = new GestureDetector(context, this);
+    }
+
+    /**
+     * Resets the UI to the intial state.
+     */
+    public void resetPositions() {
+        super.resetCoordinates();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        return mGestureDetector.onTouchEvent(event);
+    }
+
+    /*
+     * Methods below implement GestureDetector.OnGestureListener
+     */
+    @Override
+    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+        if (VERBOSE) Log.v(TAG, "onScroll(): " + distanceX + " - " + distanceY);
+        if (mFocusedLine != null) {
+            mAutofillManager.notifyViewExited(this, mFocusedLine.mFieldTextItem.id);
+        }
+        mTopMargin -= distanceY;
+        mLeftMargin -= distanceX;
+        invalidate();
+        return true;
+    }
+
+    @Override
+    public boolean onDown(MotionEvent event) {
+        onMotion((int) event.getY());
+        return true;
+    }
+
+    @Override
+    public void onShowPress(MotionEvent e) {
+    }
+
+    @Override
+    public boolean onSingleTapUp(MotionEvent e) {
+        return true;
+    }
+
+    @Override
+    public void onLongPress(MotionEvent e) {
+    }
+
+    @Override
+    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/InfoButton.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/InfoButton.java
new file mode 100644
index 0000000..92a221f
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/InfoButton.java
@@ -0,0 +1,54 @@
+/*
+ * 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 com.example.android.autofill.app.view.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.widget.AppCompatImageButton;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.example.android.autofill.app.R;
+
+public class InfoButton extends AppCompatImageButton {
+    public InfoButton(Context context) {
+        this(context, null);
+    }
+
+    public InfoButton(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public InfoButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.InfoButton,
+                defStyleAttr, 0);
+        String infoText = typedArray.getString(R.styleable.InfoButton_dialogText);
+        typedArray.recycle();
+        setInfoText(infoText);
+    }
+
+    public void setInfoText(final String infoText) {
+        setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                new AlertDialog.Builder(InfoButton.this.getContext())
+                        .setMessage(infoText).create().show();
+            }
+        });
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/NavigationItem.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/NavigationItem.java
new file mode 100644
index 0000000..9fea6bf
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/NavigationItem.java
@@ -0,0 +1,87 @@
+/*
+ * 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 com.example.android.autofill.app.view.widget;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.TypedArray;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.CardView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.example.android.autofill.app.R;
+
+import static com.example.android.autofill.app.Util.TAG;
+
+public class NavigationItem extends FrameLayout {
+    public NavigationItem(Context context) {
+        this(context, null);
+    }
+
+    public NavigationItem(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public NavigationItem(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public NavigationItem(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NavigationItem,
+                defStyleAttr, defStyleRes);
+        String labelText = typedArray.getString(R.styleable.NavigationItem_labelText);
+        String infoText = typedArray.getString(R.styleable.NavigationItem_infoText);
+        Drawable logoDrawable = typedArray.getDrawable(R.styleable.NavigationItem_itemLogo);
+        @ColorRes int colorRes = typedArray.getResourceId(R.styleable.NavigationItem_imageColor, 0);
+        String launchingActivityName = typedArray.getString(R.styleable.NavigationItem_destinationActivityName);
+        int imageColor = ContextCompat.getColor(getContext(), colorRes);
+        typedArray.recycle();
+        View rootView = LayoutInflater.from(context).inflate(R.layout.navigation_item, this);
+        TextView buttonLabel = rootView.findViewById(R.id.buttonLabel);
+        buttonLabel.setText(labelText);
+        if (logoDrawable != null) {
+            Drawable mutatedLogoDrawable = logoDrawable.mutate();
+            mutatedLogoDrawable.setColorFilter(imageColor, PorterDuff.Mode.SRC_IN);
+            buttonLabel.setCompoundDrawablesRelativeWithIntrinsicBounds(mutatedLogoDrawable, null,
+                    null, null);
+        }
+        InfoButton infoButton = rootView.findViewById(R.id.infoButton);
+        infoButton.setInfoText(infoText);
+        infoButton.setColorFilter(imageColor);
+        CardView outerView = rootView.findViewById(R.id.cardView);
+        outerView.setOnClickListener((view) -> {
+            if (launchingActivityName != null) {
+                Intent intent = new Intent();
+                intent.setClassName(getContext().getPackageName(), launchingActivityName);
+                context.startActivity(intent);
+            } else {
+                Log.w(TAG, "Launching Activity name not set.");
+            }
+        });
+    }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java
deleted file mode 100644
index b7de476..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java
+++ /dev/null
@@ -1,154 +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 com.example.android.autofillframework;
-
-import android.app.assist.AssistStructure;
-import android.app.assist.AssistStructure.ViewNode;
-import android.app.assist.AssistStructure.WindowNode;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewStructure.HtmlInfo;
-import android.view.autofill.AutofillValue;
-
-import java.util.Arrays;
-import java.util.Set;
-
-public final class CommonUtil {
-
-    public static final String TAG = "AutofillSample";
-    public static final boolean DEBUG = true;
-    public static final boolean VERBOSE = false;
-    public static final String EXTRA_DATASET_NAME = "dataset_name";
-    public static final String EXTRA_FOR_RESPONSE = "for_response";
-
-    private static void bundleToString(StringBuilder builder, Bundle data) {
-        final Set<String> keySet = data.keySet();
-        builder.append("[Bundle with ").append(keySet.size()).append(" keys:");
-        for (String key : keySet) {
-            builder.append(' ').append(key).append('=');
-            Object value = data.get(key);
-            if ((value instanceof Bundle)) {
-                bundleToString(builder, (Bundle) value);
-            } else {
-                builder.append((value instanceof Object[])
-                        ? Arrays.toString((Object[]) value) : value);
-            }
-        }
-        builder.append(']');
-    }
-
-    public static String bundleToString(Bundle data) {
-        if (data == null) {
-            return "N/A";
-        }
-        final StringBuilder builder = new StringBuilder();
-        bundleToString(builder, data);
-        return builder.toString();
-    }
-
-    public static String getTypeAsString(int type) {
-        switch (type) {
-            case View.AUTOFILL_TYPE_TEXT:
-                return "TYPE_TEXT";
-            case View.AUTOFILL_TYPE_LIST:
-                return "TYPE_LIST";
-            case View.AUTOFILL_TYPE_NONE:
-                return "TYPE_NONE";
-            case View.AUTOFILL_TYPE_TOGGLE:
-                return "TYPE_TOGGLE";
-            case View.AUTOFILL_TYPE_DATE:
-                return "TYPE_DATE";
-        }
-        return "UNKNOWN_TYPE";
-    }
-
-    private static String getAutofillValueAndTypeAsString(AutofillValue value) {
-        if (value == null) return "null";
-
-        StringBuilder builder = new StringBuilder(value.toString()).append('(');
-        if (value.isText()) {
-            builder.append("isText");
-        } else if (value.isDate()) {
-            builder.append("isDate");
-        } else if (value.isToggle()) {
-            builder.append("isToggle");
-        } else if (value.isList()) {
-            builder.append("isList");
-        }
-        return builder.append(')').toString();
-    }
-
-    public static void dumpStructure(AssistStructure structure) {
-        int nodeCount = structure.getWindowNodeCount();
-        Log.v(TAG, "dumpStructure(): component=" + structure.getActivityComponent()
-                + " numberNodes=" + nodeCount);
-        for (int i = 0; i < nodeCount; i++) {
-            Log.v(TAG, "node #" + i);
-            WindowNode node = structure.getWindowNodeAt(i);
-            dumpNode("  ", node.getRootViewNode());
-        }
-    }
-
-    private static void dumpNode(String prefix, ViewNode node) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(prefix)
-                .append("autoFillId: ").append(node.getAutofillId())
-                .append("\tidEntry: ").append(node.getIdEntry())
-                .append("\tid: ").append(node.getId())
-                .append("\tclassName: ").append(node.getClassName())
-                .append('\n');
-
-        builder.append(prefix)
-                .append("focused: ").append(node.isFocused())
-                .append("\tvisibility").append(node.getVisibility())
-                .append("\tchecked: ").append(node.isChecked())
-                .append("\twebDomain: ").append(node.getWebDomain())
-                .append("\thint: ").append(node.getHint())
-                .append('\n');
-
-        HtmlInfo htmlInfo = node.getHtmlInfo();
-
-        if (htmlInfo != null) {
-            builder.append(prefix)
-                    .append("HTML TAG: ").append(htmlInfo.getTag())
-                    .append(" attrs: ").append(htmlInfo.getAttributes())
-                    .append('\n');
-        }
-
-        String[] afHints = node.getAutofillHints();
-        CharSequence[] options = node.getAutofillOptions();
-        builder.append(prefix).append("afType: ").append(getTypeAsString(node.getAutofillType()))
-                .append("\tafValue:")
-                .append(getAutofillValueAndTypeAsString(node.getAutofillValue()))
-                .append("\tafOptions:").append(options == null ? "N/A" : Arrays.toString(options))
-                .append("\tafHints: ").append(afHints == null ? "N/A" : Arrays.toString(afHints))
-                .append("\tinputType:").append(node.getInputType())
-                .append('\n');
-
-        int numberChildren = node.getChildCount();
-        builder.append(prefix).append("# children: ").append(numberChildren)
-                .append("\ttext: ").append(node.getText())
-                .append('\n');
-
-        Log.v(TAG, builder.toString());
-        final String prefix2 = prefix + "  ";
-        for (int i = 0; i < numberChildren; i++) {
-            Log.v(TAG, prefix + "child #" + i);
-            dumpNode(prefix2, node.getChildAt(i));
-        }
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.java
deleted file mode 100644
index 83e8614..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.java
+++ /dev/null
@@ -1,83 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.autofill.AutofillManager;
-import android.widget.EditText;
-
-import com.example.android.autofillframework.R;
-
-public class CreditCardActivity extends AppCompatActivity {
-
-    private EditText mCcExpDayView;
-    private EditText mCcExpMonthView;
-    private EditText mCcExpYearView;
-    private EditText mCcNumber;
-    private EditText mCcSecurityCode;
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, CreditCardActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.credit_card_activity);
-        mCcExpDayView = findViewById(R.id.expirationDay);
-        mCcExpMonthView = findViewById(R.id.expirationMonth);
-        mCcExpYearView = findViewById(R.id.expirationYear);
-        mCcNumber = findViewById(R.id.creditCardNumberField);
-        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
-        findViewById(R.id.submitButton).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                submit();
-            }
-        });
-        findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                getSystemService(AutofillManager.class).cancel();
-                resetFields();
-            }
-        });
-    }
-
-    private void resetFields() {
-        mCcExpDayView.setText("");
-        mCcExpMonthView.setText("");
-        mCcExpYearView.setText("");
-        mCcNumber.setText("");
-        mCcSecurityCode.setText("");
-    }
-
-    /**
-     * Launches new Activity and finishes, triggering an autofill save request if the user entered
-     * any new data.
-     */
-    private void submit() {
-        Intent intent = WelcomeActivity.getStartActivityIntent(this);
-        startActivity(intent);
-        finish();
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardAntiPatternActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardAntiPatternActivity.java
deleted file mode 100644
index a7c1429..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardAntiPatternActivity.java
+++ /dev/null
@@ -1,77 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.autofill.AutofillManager;
-import android.widget.EditText;
-
-import com.example.android.autofillframework.R;
-
-public class CreditCardAntiPatternActivity extends AppCompatActivity {
-
-    private EditText mCcExpDateView;
-    private EditText mCcExpNumber;
-    private EditText mCcSecurityCode;
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, CreditCardAntiPatternActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.credit_card_anti_pattern_activity);
-        mCcExpDateView = findViewById(R.id.creditCardExpirationView);
-        mCcExpNumber = findViewById(R.id.creditCardNumberField);
-        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
-        findViewById(R.id.submitButton).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                submit();
-            }
-        });
-        findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                getSystemService(AutofillManager.class).cancel();
-                resetFields();
-            }
-        });
-    }
-
-    private void resetFields() {
-        mCcExpDateView.setText("");
-        mCcExpNumber.setText("");
-        mCcSecurityCode.setText("");
-    }
-
-    /**
-     * Launches new Activity and finishes, triggering an autofill save request if the user entered
-     * any new data.
-     */
-    private void submit() {
-        Intent intent = WelcomeActivity.getStartActivityIntent(this);
-        startActivity(intent);
-        finish();
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardCompoundViewActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardCompoundViewActivity.java
deleted file mode 100644
index 05f57d0..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardCompoundViewActivity.java
+++ /dev/null
@@ -1,77 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.autofill.AutofillManager;
-import android.widget.EditText;
-
-import com.example.android.autofillframework.R;
-
-public class CreditCardCompoundViewActivity extends AppCompatActivity {
-
-    private CreditCardExpirationDateCompoundView mCcExpDateView;
-    private EditText mCcExpNumber;
-    private EditText mCcSecurityCode;
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, CreditCardCompoundViewActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.credit_card_compound_view_activity);
-        mCcExpDateView = findViewById(R.id.creditCardExpirationView);
-        mCcExpNumber = findViewById(R.id.creditCardNumberField);
-        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
-        findViewById(R.id.submitButton).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                submit();
-            }
-        });
-        findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                getSystemService(AutofillManager.class).cancel();
-                resetFields();
-            }
-        });
-    }
-
-    private void resetFields() {
-        mCcExpDateView.reset();
-        mCcExpNumber.setText("");
-        mCcSecurityCode.setText("");
-    }
-
-    /**
-     * Launches new Activity and finishes, triggering an autofill save request if the user entered
-     * any new data.
-     */
-    private void submit() {
-        Intent intent = WelcomeActivity.getStartActivityIntent(this);
-        startActivity(intent);
-        finish();
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardDatePickerActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardDatePickerActivity.java
deleted file mode 100644
index 940f5e4..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardDatePickerActivity.java
+++ /dev/null
@@ -1,91 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.view.View;
-import android.view.autofill.AutofillManager;
-import android.widget.EditText;
-
-import com.example.android.autofillframework.R;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-public class CreditCardDatePickerActivity extends AppCompatActivity {
-
-    private CreditCardExpirationDatePickerView mCcExpDateView;
-    private EditText mCcExpNumber;
-    private EditText mCcSecurityCode;
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, CreditCardDatePickerActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.credit_card_date_picker_activity);
-        mCcExpDateView = findViewById(R.id.creditCardExpirationView);
-        mCcExpNumber = findViewById(R.id.creditCardNumberField);
-        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
-        findViewById(R.id.submitButton).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                submit();
-            }
-        });
-        findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                getSystemService(AutofillManager.class).cancel();
-                resetFields();
-            }
-        });
-
-        mCcExpDateView.reset();
-    }
-
-    private void resetFields() {
-        mCcExpDateView.reset();
-        mCcExpNumber.setText("");
-        mCcSecurityCode.setText("");
-    }
-
-    public void showDatePickerDialog(View v) {
-        if (v != mCcExpDateView) {
-            Log.w(TAG, "showDatePickerDialog() called on invalid view: " + v);
-            return;
-        }
-        mCcExpDateView.showDatePickerDialog(getSupportFragmentManager());
-    }
-
-
-    /**
-     * Launches new Activity and finishes, triggering an autofill save request if the user entered
-     * any new data.
-     */
-    private void submit() {
-        Intent intent = WelcomeActivity.getStartActivityIntent(this);
-        startActivity(intent);
-        finish();
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDateCompoundView.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDateCompoundView.java
deleted file mode 100644
index afa105e..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDateCompoundView.java
+++ /dev/null
@@ -1,135 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillValue;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.FrameLayout;
-import android.widget.Spinner;
-
-import com.example.android.autofillframework.R;
-
-import java.util.Calendar;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * A custom view that represents a {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} using
- * 2 {@link Spinner spinners} to represent the credit card expiration month and year.
- */
-public class CreditCardExpirationDateCompoundView extends FrameLayout {
-
-    private static final int CC_EXP_YEARS_COUNT = 5;
-
-    private final String[] mYears = new String[CC_EXP_YEARS_COUNT];
-
-    private Spinner mCcExpMonthSpinner;
-    private Spinner mCcExpYearSpinner;
-
-    public CreditCardExpirationDateCompoundView(@NonNull Context context) {
-        this(context, null);
-    }
-
-    public CreditCardExpirationDateCompoundView(@NonNull Context context,
-            @Nullable AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public CreditCardExpirationDateCompoundView(@NonNull Context context,
-            @Nullable AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public CreditCardExpirationDateCompoundView(@NonNull final Context context,
-            @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        View rootView = LayoutInflater.from(context).inflate(R.layout.cc_exp_date, this);
-        mCcExpMonthSpinner = rootView.findViewById(R.id.ccExpMonth);
-        mCcExpYearSpinner = rootView.findViewById(R.id.ccExpYear);
-        setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS);
-        ArrayAdapter<CharSequence> monthAdapter = ArrayAdapter.createFromResource
-                (context, R.array.month_array, android.R.layout.simple_spinner_item);
-        monthAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        mCcExpMonthSpinner.setAdapter(monthAdapter);
-        int year = Calendar.getInstance().get(Calendar.YEAR);
-        for (int i = 0; i < mYears.length; i++) {
-            mYears[i] = Integer.toString(year + i);
-        }
-        mCcExpYearSpinner.setAdapter(new ArrayAdapter<>(context,
-                android.R.layout.simple_spinner_item, mYears));
-        AdapterView.OnItemSelectedListener onItemSelectedListener =
-                new AdapterView.OnItemSelectedListener() {
-                    @Override
-                    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-                        context.getSystemService(AutofillManager.class)
-                                .notifyValueChanged(CreditCardExpirationDateCompoundView.this);
-                    }
-
-                    @Override
-                    public void onNothingSelected(AdapterView<?> parent) {
-                    }
-                };
-        mCcExpMonthSpinner.setOnItemSelectedListener(onItemSelectedListener);
-        mCcExpYearSpinner.setOnItemSelectedListener(onItemSelectedListener);
-    }
-
-    @Override
-    public AutofillValue getAutofillValue() {
-        Calendar calendar = Calendar.getInstance();
-        // Set hours, minutes, seconds, and millis to 0 to ensure getAutofillValue() == the value
-        // set by autofill(). Without this line, the view will not turn yellow when updated.
-        calendar.clear();
-        int year = Integer.parseInt(mCcExpYearSpinner.getSelectedItem().toString());
-        int month = mCcExpMonthSpinner.getSelectedItemPosition();
-        calendar.set(Calendar.YEAR, year);
-        calendar.set(Calendar.MONTH, month);
-        long unixTime = calendar.getTimeInMillis();
-        return AutofillValue.forDate(unixTime);
-    }
-
-    @Override
-    public void autofill(AutofillValue value) {
-        if (!value.isDate()) {
-            Log.w(TAG, "Ignoring autofill() because service sent a non-date value:" + value);
-            return;
-        }
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTimeInMillis(value.getDateValue());
-        int month = calendar.get(Calendar.MONTH);
-        int year = calendar.get(Calendar.YEAR);
-        mCcExpMonthSpinner.setSelection(month);
-        mCcExpYearSpinner.setSelection(year - Integer.parseInt(mYears[0]));
-    }
-
-    @Override
-    public int getAutofillType() {
-        return AUTOFILL_TYPE_DATE;
-    }
-
-    public void reset() {
-        mCcExpMonthSpinner.setSelection(0);
-        mCcExpYearSpinner.setSelection(0);
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDatePickerView.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDatePickerView.java
deleted file mode 100644
index e8385fb..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDatePickerView.java
+++ /dev/null
@@ -1,164 +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 com.example.android.autofillframework.app;
-
-import android.app.DatePickerDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v7.widget.AppCompatEditText;
-import android.text.format.DateFormat;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.view.autofill.AutofillValue;
-import android.widget.DatePicker;
-import android.widget.EditText;
-
-import com.example.android.autofillframework.R;
-
-import java.util.Calendar;
-import java.util.Date;
-
-import static com.example.android.autofillframework.CommonUtil.DEBUG;
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * A custom view that represents a {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} using
- * a non-editable {@link EditText} that triggers a {@link DatePickerDialog} to represent the
- * credit card expiration month and year.
- */
-public class CreditCardExpirationDatePickerView extends AppCompatEditText {
-
-    private static final int CC_EXP_YEARS_COUNT = 5;
-
-    /**
-     * Calendar instance used for month / year calculations. Should be reset before each use.
-     */
-    private final Calendar mTempCalendar;
-
-    private int mMonth;
-    private int mYear;
-
-    public CreditCardExpirationDatePickerView(@NonNull Context context) {
-        this(context, null);
-    }
-
-    public CreditCardExpirationDatePickerView(@NonNull Context context,
-            @Nullable AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public CreditCardExpirationDatePickerView(@NonNull Context context,
-            @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        // Use the current date as the initial date in the picker.
-        mTempCalendar = Calendar.getInstance();
-        mYear = mTempCalendar.get(Calendar.YEAR);
-        mMonth = mTempCalendar.get(Calendar.MONTH);
-    }
-
-    /**
-     * Gets a temporary calendar set with the View's year and month.
-     */
-    private Calendar getCalendar() {
-        mTempCalendar.clear();
-        mTempCalendar.set(Calendar.YEAR, mYear);
-        mTempCalendar.set(Calendar.MONTH, mMonth);
-        mTempCalendar.set(Calendar.DATE, 1);
-        return mTempCalendar;
-    }
-
-    @Override
-    public AutofillValue getAutofillValue() {
-        Calendar c = getCalendar();
-        AutofillValue value = AutofillValue.forDate(c.getTimeInMillis());
-        if (DEBUG) Log.d(TAG, "getAutofillValue(): " + value);
-        return value;
-    }
-
-    @Override
-    public void autofill(AutofillValue value) {
-        if (value == null || !value.isDate()) {
-            Log.w(TAG, "autofill(): invalid value " + value);
-            return;
-        }
-        long time = value.getDateValue();
-        mTempCalendar.setTimeInMillis(time);
-        int year = mTempCalendar.get(Calendar.YEAR);
-        int month = mTempCalendar.get(Calendar.MONTH);
-        if (DEBUG) Log.d(TAG, "autofill(" + value + "): " + month + "/" + year);
-        setDate(year, month);
-    }
-
-    private void setDate(int year, int month) {
-        mYear = year;
-        mMonth = month;
-        Date selectedDate = new Date(getCalendar().getTimeInMillis());
-        String dateString = DateFormat.getDateFormat(getContext()).format(selectedDate);
-        setText(dateString);
-    }
-
-    @Override
-    public int getAutofillType() {
-        return AUTOFILL_TYPE_DATE;
-    }
-
-    public void reset() {
-        mTempCalendar.setTimeInMillis(System.currentTimeMillis());
-        setDate(mTempCalendar.get(Calendar.YEAR), mTempCalendar.get(Calendar.MONTH));
-    }
-
-    public void showDatePickerDialog(FragmentManager fragmentManager) {
-        DatePickerFragment newFragment = new DatePickerFragment();
-        newFragment.mParent = this;
-        newFragment.show(fragmentManager, "datePicker");
-    }
-
-    public static class DatePickerFragment extends DialogFragment
-            implements DatePickerDialog.OnDateSetListener {
-
-        private CreditCardExpirationDatePickerView mParent;
-
-        @Override
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            DatePickerDialog dialog = new DatePickerDialog(getActivity(),
-                    R.style.CustomDatePickerDialogTheme, this, mParent.mYear, mParent.mMonth, 1);
-
-            DatePicker datePicker = dialog.getDatePicker();
-
-            // Limit range.
-            Calendar c = mParent.getCalendar();
-            datePicker.setMinDate(c.getTimeInMillis());
-            c.set(Calendar.YEAR, mParent.mYear + CC_EXP_YEARS_COUNT - 1);
-            datePicker.setMaxDate(c.getTimeInMillis());
-
-            // Remove day.
-            datePicker.findViewById(getResources().getIdentifier("day", "id", "android"))
-                    .setVisibility(View.GONE);
-            return dialog;
-        }
-
-        @Override
-        public void onDateSet(DatePicker view, int year, int month, int day) {
-            mParent.setDate(year, month);
-        }
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardSpinnersActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardSpinnersActivity.java
deleted file mode 100644
index af1bed5..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardSpinnersActivity.java
+++ /dev/null
@@ -1,124 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.autofill.AutofillManager;
-import android.widget.ArrayAdapter;
-import android.widget.EditText;
-import android.widget.Spinner;
-
-import com.example.android.autofillframework.R;
-
-import java.util.Calendar;
-
-public class CreditCardSpinnersActivity extends AppCompatActivity {
-
-    private static final int CC_EXP_YEARS_COUNT = 5;
-
-    private final String[] years = new String[CC_EXP_YEARS_COUNT];
-
-    private Spinner mCcExpirationDaySpinner;
-    private Spinner mCcExpirationMonthSpinner;
-    private Spinner mCcExpirationYearSpinner;
-    private EditText mCcCardNumber;
-    private EditText mCcSecurityCode;
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, CreditCardSpinnersActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.credit_card_spinners_activity);
-        mCcExpirationDaySpinner = findViewById(R.id.expirationDay);
-        mCcExpirationMonthSpinner = findViewById(R.id.expirationMonth);
-        mCcExpirationYearSpinner = findViewById(R.id.expirationYear);
-        mCcCardNumber = findViewById(R.id.creditCardNumberField);
-        mCcSecurityCode = findViewById(R.id.creditCardSecurityCode);
-
-        // Create an ArrayAdapter using the string array and a default spinner layout
-        ArrayAdapter<CharSequence> dayAdapter = ArrayAdapter.createFromResource
-                (this, R.array.day_array, android.R.layout.simple_spinner_item);
-        // Specify the layout to use when the list of choices appears
-        dayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        // Apply the adapter to the spinner
-        mCcExpirationDaySpinner.setAdapter(dayAdapter);
-
-        /*
-        R.array.month_array could be an array of Strings like "Jan", "Feb", "March", etc., and
-        the AutofillService would know how to autofill it. However, for the sake of keeping the
-        AutofillService simple, we will stick to a list of numbers (1, 2, ... 12) to represent
-        months; it makes it much easier to generate fake autofill data in the service that can still
-        autofill this spinner.
-        */
-        ArrayAdapter<CharSequence> monthAdapter = ArrayAdapter.createFromResource(
-                this, R.array.month_array, android.R.layout.simple_spinner_item);
-        // Adapter created from resource has getAutofillOptions() implemented by default.
-        monthAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        mCcExpirationMonthSpinner.setAdapter(monthAdapter);
-
-        int year = Calendar.getInstance().get(Calendar.YEAR);
-        for (int i = 0; i < years.length; i++) {
-            years[i] = Integer.toString(year + i);
-        }
-        // Since the years Spinner uses a custom adapter, it needs to implement getAutofillOptions.
-        mCcExpirationYearSpinner.setAdapter(
-                new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, years) {
-                    @Override
-                    public CharSequence[] getAutofillOptions() {
-                        return years;
-                    }
-                });
-        findViewById(R.id.submit).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                submit();
-            }
-        });
-        findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                getSystemService(AutofillManager.class).cancel();
-                resetFields();
-            }
-        });
-    }
-
-    private void resetFields() {
-        mCcExpirationDaySpinner.setSelection(0);
-        mCcExpirationMonthSpinner.setSelection(0);
-        mCcExpirationYearSpinner.setSelection(0);
-        mCcCardNumber.setText("");
-        mCcSecurityCode.setText("");
-    }
-
-    /**
-     * Launches new Activity and finishes, triggering an autofill save request if the user entered
-     * any new data.
-     */
-    private void submit() {
-        Intent intent = WelcomeActivity.getStartActivityIntent(CreditCardSpinnersActivity.this);
-        startActivity(intent);
-        finish();
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.java
deleted file mode 100644
index f6fb3a5..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.java
+++ /dev/null
@@ -1,490 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.Rect;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewStructure;
-import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillValue;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.example.android.autofillframework.CommonUtil;
-import com.example.android.autofillframework.R;
-import com.google.common.base.Preconditions;
-
-import java.text.DateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-
-import static com.example.android.autofillframework.CommonUtil.bundleToString;
-
-/**
- * A custom View with a virtual structure for fields supporting {@link View#getAutofillHints()}
- */
-public class CustomVirtualView extends View {
-
-    protected static final boolean DEBUG = true;
-    protected static final boolean VERBOSE = false;
-    private static final String TAG = "CustomView";
-    private static final int DEFAULT_TEXT_HEIGHT_DP = 34;
-    private static final int VERTICAL_GAP = 10;
-    private static final int UNFOCUSED_COLOR = Color.BLACK;
-    private static final int FOCUSED_COLOR = Color.RED;
-    private static int sNextId;
-    protected final AutofillManager mAutofillManager;
-    private final ArrayList<Line> mVirtualViewGroups = new ArrayList<>();
-    private final SparseArray<Item> mVirtualViews = new SparseArray<>();
-    private final SparseArray<Partition> mPartitionsByAutofillId = new SparseArray<>();
-    private final ArrayMap<String, Partition> mPartitionsByName = new ArrayMap<>();
-    protected Line mFocusedLine;
-    protected int mTopMargin;
-    protected int mLeftMargin;
-    private Paint mTextPaint;
-    private int mTextHeight;
-    private int mLineLength;
-
-    public CustomVirtualView(Context context) {
-        this(context, null);
-    }
-
-    public CustomVirtualView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public CustomVirtualView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public CustomVirtualView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mAutofillManager = context.getSystemService(AutofillManager.class);
-        mTextPaint = new Paint();
-        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomVirtualView,
-                defStyleAttr, defStyleRes);
-        int defaultHeight =
-                (int) (DEFAULT_TEXT_HEIGHT_DP * getResources().getDisplayMetrics().density);
-        mTextHeight = typedArray.getDimensionPixelSize(
-                R.styleable.CustomVirtualView_internalTextSize, defaultHeight);
-        typedArray.recycle();
-        resetCoordinates();
-    }
-
-    protected void resetCoordinates() {
-        mTextPaint.setStyle(Style.FILL);
-        mTextPaint.setTextSize(mTextHeight);
-        mTopMargin = getPaddingTop();
-        mLeftMargin = getPaddingStart();
-        mLineLength = mTextHeight + VERTICAL_GAP;
-    }
-
-    @Override
-    public void autofill(SparseArray<AutofillValue> values) {
-        Context context = getContext();
-
-        // User has just selected a Dataset from the list of autofill suggestions.
-        // The Dataset is comprised of a list of AutofillValues, with each AutofillValue meant
-        // to fill a specific autofillable view. Now we have to update the UI based on the
-        // AutofillValues in the list, but first we make sure all autofilled values belong to the
-        // same partition
-        if (DEBUG) Log.d(TAG, "autofill(): " + values);
-
-        // First get the name of all partitions in the values
-        ArraySet<String> partitions = new ArraySet<>();
-        for (int i = 0; i < values.size(); i++) {
-            int id = values.keyAt(i);
-            Partition partition = mPartitionsByAutofillId.get(id);
-            if (partition == null) {
-                showError(context.getString(R.string.message_autofill_no_partitions, id,
-                        mPartitionsByAutofillId));
-                return;
-            }
-            partitions.add(partition.mName);
-        }
-
-        // Then make sure they follow the Highlander rule (There can be only one)
-        if (partitions.size() != 1) {
-            showError(context.getString(R.string.message_autofill_blocked, partitions));
-            return;
-        }
-
-        // Finally, autofill it.
-        DateFormat df = android.text.format.DateFormat.getDateFormat(context);
-        for (int i = 0; i < values.size(); i++) {
-            int id = values.keyAt(i);
-            AutofillValue value = values.valueAt(i);
-            Item item = mVirtualViews.get(id);
-
-            if (item == null) {
-                Log.w(TAG, "No item for id " + id);
-                continue;
-            }
-
-            if (!item.editable) {
-                showError(context.getString(R.string.message_autofill_readonly, item.text));
-                continue;
-            }
-
-            // Check if the type was properly set by the autofill service
-            if (DEBUG) {
-                Log.d(TAG, "Validating " + i
-                        + ": expectedType=" + CommonUtil.getTypeAsString(item.type)
-                        + "(" + item.type + "), value=" + value);
-            }
-            boolean valid = false;
-            if (value.isText() && item.type == AUTOFILL_TYPE_TEXT) {
-                item.text = value.getTextValue();
-                valid = true;
-            } else if (value.isDate() && item.type == AUTOFILL_TYPE_DATE) {
-                item.text = df.format(new Date(value.getDateValue()));
-                valid = true;
-            } else {
-                Log.w(TAG, "Unsupported type: " + value);
-            }
-            if (!valid) {
-                item.text = context.getString(R.string.message_autofill_invalid);
-            }
-        }
-        postInvalidate();
-        showMessage(context.getString(R.string.message_autofill_ok, partitions.valueAt(0)));
-    }
-
-    @Override
-    public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
-        // Build a ViewStructure that will get passed to the AutofillService by the framework
-        // when it is time to find autofill suggestions.
-        structure.setClassName(getClass().getName());
-        int childrenSize = mVirtualViews.size();
-        if (DEBUG) {
-            Log.d(TAG, "onProvideAutofillVirtualStructure(): flags = " + flags + ", items = "
-                    + childrenSize + ", extras: " + bundleToString(structure.getExtras()));
-        }
-        int index = structure.addChildCount(childrenSize);
-        // Traverse through the view hierarchy, including virtual child views. For each view, we
-        // need to set the relevant autofill metadata and add it to the ViewStructure.
-        for (int i = 0; i < childrenSize; i++) {
-            Item item = mVirtualViews.valueAt(i);
-            if (DEBUG) Log.d(TAG, "Adding new child at index " + index + ": " + item);
-            ViewStructure child = structure.newChild(index);
-            child.setAutofillId(structure.getAutofillId(), item.id);
-            child.setAutofillHints(item.hints);
-            child.setAutofillType(item.type);
-            child.setAutofillValue(item.getAutofillValue());
-            child.setDataIsSensitive(!item.sanitized);
-            child.setFocused(item.focused);
-            child.setVisibility(View.VISIBLE);
-            child.setDimens(item.line.mBounds.left, item.line.mBounds.top, 0, 0,
-                    item.line.mBounds.width(), item.line.mBounds.height());
-            child.setId(item.id, getContext().getPackageName(), null, item.idEntry);
-            child.setClassName(item.getClassName());
-            child.setDimens(item.line.mBounds.left, item.line.mBounds.top, 0, 0,
-                    item.line.mBounds.width(), item.line.mBounds.height());
-            index++;
-        }
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        if (VERBOSE) {
-            Log.v(TAG, "onDraw(): " + mVirtualViewGroups.size() + " lines; canvas:" + canvas);
-        }
-        float x;
-        float y = mTopMargin + mLineLength;
-        for (int i = 0; i < mVirtualViewGroups.size(); i++) {
-            Line line = mVirtualViewGroups.get(i);
-            x = mLeftMargin;
-            if (VERBOSE) Log.v(TAG, "Drawing '" + line + "' at " + x + "x" + y);
-            mTextPaint.setColor(line.mFieldTextItem.focused ? FOCUSED_COLOR : UNFOCUSED_COLOR);
-            String readOnlyText = line.mLabelItem.text + ":  [";
-            String writeText = line.mFieldTextItem.text + "]";
-            // Paints the label first...
-            canvas.drawText(readOnlyText, x, y, mTextPaint);
-            // ...then paints the edit text and sets the proper boundary
-            float deltaX = mTextPaint.measureText(readOnlyText);
-            x += deltaX;
-            line.mBounds.set((int) x, (int) (y - mLineLength),
-                    (int) (x + mTextPaint.measureText(writeText)), (int) y);
-            if (VERBOSE) Log.v(TAG, "setBounds(" + x + ", " + y + "): " + line.mBounds);
-            canvas.drawText(writeText, x, y, mTextPaint);
-            y += mLineLength;
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        int y = (int) event.getY();
-        onMotion(y);
-        return super.onTouchEvent(event);
-    }
-
-    /**
-     * Handles a motion event.
-     *
-     * @param y y coordinate.
-     */
-    protected void onMotion(int y) {
-        if (DEBUG) {
-            Log.d(TAG, "onMotion(): y=" + y + ", range=" + mLineLength + ", top=" + mTopMargin);
-        }
-        int lowerY = mTopMargin;
-        int upperY = -1;
-        for (int i = 0; i < mVirtualViewGroups.size(); i++) {
-            Line line = mVirtualViewGroups.get(i);
-            upperY = lowerY + mLineLength;
-            if (DEBUG) Log.d(TAG, "Line " + i + " ranges from " + lowerY + " to " + upperY);
-            if (lowerY <= y && y <= upperY) {
-                if (mFocusedLine != null) {
-                    Log.d(TAG, "Removing focus from " + mFocusedLine);
-                    mFocusedLine.changeFocus(false);
-                }
-                Log.d(TAG, "Changing focus to " + line);
-                mFocusedLine = line;
-                mFocusedLine.changeFocus(true);
-                invalidate();
-                break;
-            }
-            lowerY += mLineLength;
-        }
-    }
-
-    /**
-     * Creates a new partition with the given name.
-     *
-     * @throws IllegalArgumentException if such partition already exists.
-     */
-    public Partition addPartition(String name) {
-        Preconditions.checkNotNull(name, "Name cannot be null.");
-        Preconditions.checkArgument(!mPartitionsByName.containsKey(name),
-                "Partition with such name already exists.");
-        Partition partition = new Partition(name);
-        mPartitionsByName.put(name, partition);
-        return partition;
-    }
-
-    private void showError(String message) {
-        showMessage(true, message);
-    }
-
-    private void showMessage(String message) {
-        showMessage(false, message);
-    }
-
-    private void showMessage(boolean warning, String message) {
-        if (warning) {
-            Log.w(TAG, message);
-        } else {
-            Log.i(TAG, message);
-        }
-        Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
-    }
-
-
-    protected static final class Item {
-        protected final int id;
-        private final String idEntry;
-        private final Line line;
-        private final boolean editable;
-        private final boolean sanitized;
-        private final String[] hints;
-        private final int type;
-        private CharSequence text;
-        private boolean focused = false;
-        private long date;
-
-        Item(Line line, int id, String idEntry, String[] hints, int type, CharSequence text,
-                boolean editable, boolean sanitized) {
-            this.line = line;
-            this.id = id;
-            this.idEntry = idEntry;
-            this.text = text;
-            this.editable = editable;
-            this.sanitized = sanitized;
-            this.hints = hints;
-            this.type = type;
-        }
-
-        @Override
-        public String toString() {
-            return id + "/" + idEntry + ": "
-                    + (type == AUTOFILL_TYPE_DATE ? date : text) // TODO: use DateFormat for date
-                    + " (" + CommonUtil.getTypeAsString(type) + ")"
-                    + (editable ? " (editable)" : " (read-only)"
-                    + (sanitized ? " (sanitized)" : " (sensitive"))
-                    + (hints == null ? " (no hints)" : " ( " + Arrays.toString(hints) + ")");
-        }
-
-        public String getClassName() {
-            return editable ? EditText.class.getName() : TextView.class.getName();
-        }
-
-        public AutofillValue getAutofillValue() {
-            switch (type) {
-                case AUTOFILL_TYPE_TEXT:
-                    return (TextUtils.getTrimmedLength(text) > 0)
-                            ? AutofillValue.forText(text)
-                            : null;
-                case AUTOFILL_TYPE_DATE:
-                    return AutofillValue.forDate(date);
-                default:
-                    return null;
-            }
-        }
-    }
-
-    /**
-     * A partition represents a logical group of items, such as credit card info.
-     */
-    public final class Partition {
-        private final String mName;
-        private final SparseArray<Line> mLines = new SparseArray<>();
-
-        private Partition(String name) {
-            mName = name;
-        }
-
-        /**
-         * Adds a new line (containining a label and an input field) to the view.
-         *
-         * @param idEntryPrefix id prefix used to identify the line - label node will be suffixed
-         *                      with {@code Label} and editable node with {@code Field}.
-         * @param autofillType  {@link View#getAutofillType() autofill type} of the field.
-         * @param label         text used in the label.
-         * @param text          initial text used in the input field.
-         * @param sensitive     whether the input is considered sensitive.
-         * @param autofillHints list of autofill hints.
-         * @return the new line.
-         */
-        public Line addLine(String idEntryPrefix, int autofillType, String label, String text,
-                boolean sensitive, String... autofillHints) {
-            Preconditions.checkArgument(autofillType == AUTOFILL_TYPE_TEXT ||
-                    autofillType == AUTOFILL_TYPE_DATE, "Unsupported type: " + autofillType);
-            Line line = new Line(idEntryPrefix, autofillType, label, autofillHints, text,
-                    !sensitive);
-            mVirtualViewGroups.add(line);
-            int id = line.mFieldTextItem.id;
-            mLines.put(id, line);
-            mVirtualViews.put(line.mLabelItem.id, line.mLabelItem);
-            mVirtualViews.put(id, line.mFieldTextItem);
-            mPartitionsByAutofillId.put(id, this);
-
-            return line;
-        }
-
-        /**
-         * Resets the value of all items in the partition.
-         */
-        public void reset() {
-            for (int i = 0; i < mLines.size(); i++) {
-                mLines.valueAt(i).reset();
-            }
-        }
-
-        @Override
-        public String toString() {
-            return mName;
-        }
-    }
-
-    /**
-     * A line in the virtual view contains a label and an input field.
-     */
-    public final class Line {
-
-        protected final Item mFieldTextItem;
-        // Boundaries of the text field, relative to the CustomView
-        private final Rect mBounds = new Rect();
-        private final Item mLabelItem;
-        private final int mAutofillType;
-
-        private Line(String idEntryPrefix, int autofillType, String label, String[] hints,
-                String text, boolean sanitized) {
-            this.mAutofillType = autofillType;
-            this.mLabelItem = new Item(this, ++sNextId, idEntryPrefix + "Label", null,
-                    AUTOFILL_TYPE_NONE, label, false, true);
-            this.mFieldTextItem = new Item(this, ++sNextId, idEntryPrefix + "Field", hints,
-                    autofillType, text, true, sanitized);
-        }
-
-        private void changeFocus(boolean focused) {
-            mFieldTextItem.focused = focused;
-            if (focused) {
-                Rect absBounds = getAbsCoordinates();
-                if (DEBUG) {
-                    Log.d(TAG, "focus gained on " + mFieldTextItem.id + "; absBounds=" + absBounds);
-                }
-                mAutofillManager.notifyViewEntered(CustomVirtualView.this, mFieldTextItem.id,
-                        absBounds);
-            } else {
-                if (DEBUG) Log.d(TAG, "focus lost on " + mFieldTextItem.id);
-                mAutofillManager.notifyViewExited(CustomVirtualView.this, mFieldTextItem.id);
-            }
-        }
-
-        private Rect getAbsCoordinates() {
-            // Must offset the boundaries so they're relative to the CustomView.
-            int offset[] = new int[2];
-            getLocationOnScreen(offset);
-            Rect absBounds = new Rect(mBounds.left + offset[0],
-                    mBounds.top + offset[1],
-                    mBounds.right + offset[0], mBounds.bottom + offset[1]);
-            if (VERBOSE) {
-                Log.v(TAG, "getAbsCoordinates() for " + mFieldTextItem.id + ": bounds=" + mBounds
-                        + " offset: " + Arrays.toString(offset) + " absBounds: " + absBounds);
-            }
-            return absBounds;
-        }
-
-        /**
-         * Gets the value of the input field text.
-         */
-        public CharSequence getText() {
-            return mFieldTextItem.text;
-        }
-
-        /**
-         * Resets the value of the input field text.
-         */
-        public void reset() {
-            mFieldTextItem.text = "        ";
-        }
-
-        @Override
-        public String toString() {
-            return "Label: " + mLabelItem + " Text: " + mFieldTextItem + " Focused: " +
-                    mFieldTextItem.focused + " Type: " + mAutofillType;
-        }
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/EmailComposeActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/EmailComposeActivity.java
deleted file mode 100644
index 957d7aa..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/EmailComposeActivity.java
+++ /dev/null
@@ -1,46 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-
-import com.example.android.autofillframework.R;
-
-public class EmailComposeActivity extends AppCompatActivity {
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, EmailComposeActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.email_compose_activity);
-        findViewById(R.id.sendButton).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(WelcomeActivity.getStartActivityIntent(EmailComposeActivity.this));
-                finish();
-            }
-        });
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/InfoButton.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/InfoButton.java
deleted file mode 100644
index d5811e1..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/InfoButton.java
+++ /dev/null
@@ -1,54 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.AppCompatImageButton;
-import android.util.AttributeSet;
-import android.view.View;
-
-import com.example.android.autofillframework.R;
-
-public class InfoButton extends AppCompatImageButton {
-    public InfoButton(Context context) {
-        this(context, null);
-    }
-
-    public InfoButton(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public InfoButton(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.InfoButton,
-                defStyleAttr, 0);
-        String infoText = typedArray.getString(R.styleable.InfoButton_dialogText);
-        typedArray.recycle();
-        setInfoText(infoText);
-    }
-
-    public void setInfoText(final String infoText) {
-        setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                new AlertDialog.Builder(InfoButton.this.getContext())
-                        .setMessage(infoText).create().show();
-            }
-        });
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.java
deleted file mode 100644
index 0e139f9..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.java
+++ /dev/null
@@ -1,143 +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 com.example.android.autofillframework.app;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.view.View;
-
-import com.example.android.autofillframework.R;
-
-/**
- * This is used to launch sample activities that showcase autofill.
- */
-public class MainActivity extends AppCompatActivity {
-
-    private static final String TAG = "MainActivity";
-
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        if (launchTrampolineActivity()) {
-            return;
-        }
-
-        setContentView(R.layout.activity_main);
-        NavigationItem loginEditTexts = findViewById(R.id.standardViewSignInButton);
-        NavigationItem loginCustomVirtual = findViewById(R.id.virtualViewSignInButton);
-        NavigationItem creditCard = findViewById(R.id.creditCardButton);
-        NavigationItem creditCardSpinners = findViewById(R.id.creditCardSpinnersButton);
-        NavigationItem loginAutoComplete = findViewById(R.id.standardLoginWithAutoCompleteButton);
-        NavigationItem emailCompose = findViewById(R.id.emailComposeButton);
-        NavigationItem creditCardCompoundView = findViewById(R.id.creditCardCompoundViewButton);
-        NavigationItem creditCardDatePicker = findViewById(R.id.creditCardDatePickerButton);
-        NavigationItem creditCardAntiPatternPicker = findViewById(R.id.creditCardAntiPatternButton);
-        NavigationItem multiplePartitions = findViewById(R.id.multiplePartitionsButton);
-        NavigationItem loginWebView = findViewById(R.id.webviewSignInButton);
-        loginEditTexts.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(StandardSignInActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        loginCustomVirtual.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(VirtualSignInActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        creditCard.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(CreditCardActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        creditCardSpinners.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(CreditCardSpinnersActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        loginAutoComplete.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(StandardAutoCompleteSignInActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        emailCompose.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(EmailComposeActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        creditCardCompoundView.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(CreditCardCompoundViewActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        creditCardDatePicker.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(CreditCardDatePickerActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        creditCardAntiPatternPicker.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startActivity(CreditCardAntiPatternActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        multiplePartitions.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startActivity(MultiplePartitionsActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-        loginWebView.setNavigationButtonClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startActivity(WebViewSignInActivity.getStartActivityIntent(MainActivity.this));
-            }
-        });
-    }
-
-    private boolean launchTrampolineActivity() {
-        Intent intent = getIntent();
-        if (intent != null) {
-            String target = intent.getStringExtra("target");
-            if (target != null) {
-                Log.i(TAG, "trampolining into " + target + " instead");
-                try {
-                    Intent newIntent = new Intent(this,
-                            Class.forName("com.example.android.autofillframework." + target));
-                    newIntent.putExtras(intent);
-                    newIntent.removeExtra("target");
-                    getApplicationContext().startActivity(newIntent);
-                    finish();
-                    return true;
-                } catch (Exception e) {
-                    Log.e(TAG, "Error launching " + target, e);
-                }
-            }
-        }
-        return false;
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MultiplePartitionsActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MultiplePartitionsActivity.java
deleted file mode 100644
index 319ed19..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MultiplePartitionsActivity.java
+++ /dev/null
@@ -1,126 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.autofill.AutofillManager;
-import android.widget.Toast;
-
-import com.example.android.autofillframework.CommonUtil;
-import com.example.android.autofillframework.R;
-
-/**
- * Activity used to demonstrated safe partitioning of data.
- * <p>
- * <p>It has multiple partitions, but only accepts autofill on each partition at time.
- */
-/*
- * TODO list
- *
- * - Fix top margin.
- * - Use a combo box to select if credit card expiration date is expressed as date or text.
- * - Use a dedicated TextView (instead of Toast) for error messages.
- * - Use wrap_context to CustomView container.
- * - Use different background color (or borders) for each partition.
- * - Add more partitions (like address) - should match same partitions from service.
- * - Add more hints (like w3c ones) - should match same hints from service.
- */
-public class MultiplePartitionsActivity extends AppCompatActivity {
-
-    private ScrollableCustomVirtualView mCustomVirtualView;
-    private AutofillManager mAutofillManager;
-
-    private CustomVirtualView.Partition mCredentialsPartition;
-    private CustomVirtualView.Partition mCcPartition;
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, MultiplePartitionsActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.multiple_partitions_activity);
-
-        mCustomVirtualView = findViewById(R.id.custom_view);
-
-
-        mCredentialsPartition =
-                mCustomVirtualView.addPartition(getString(R.string.partition_credentials));
-        mCredentialsPartition.addLine("username", View.AUTOFILL_TYPE_TEXT,
-                getString(R.string.username_label),
-                "         ", false, View.AUTOFILL_HINT_USERNAME);
-        mCredentialsPartition.addLine("password", View.AUTOFILL_TYPE_TEXT,
-                getString(R.string.password_label),
-                "         ", true, View.AUTOFILL_HINT_PASSWORD);
-
-        int ccExpirationType = View.AUTOFILL_TYPE_DATE;
-        // TODO: add a checkbox to switch between text / date instead
-        Intent intent = getIntent();
-        if (intent != null) {
-            int newType = intent.getIntExtra("dateType", -1);
-            if (newType != -1) {
-                ccExpirationType = newType;
-                String typeMessage = getString(R.string.message_credit_card_expiration_type,
-                        CommonUtil.getTypeAsString(ccExpirationType));
-                // TODO: display type in a header or proper status widget
-                Toast.makeText(getApplicationContext(), typeMessage, Toast.LENGTH_LONG).show();
-            }
-        }
-
-        mCcPartition = mCustomVirtualView.addPartition(getString(R.string.partition_credit_card));
-        mCcPartition.addLine("ccNumber", View.AUTOFILL_TYPE_TEXT,
-                getString(R.string.credit_card_number_label),
-                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_NUMBER);
-        mCcPartition.addLine("ccDay", View.AUTOFILL_TYPE_TEXT,
-                getString(R.string.credit_card_expiration_day_label),
-                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY);
-        mCcPartition.addLine("ccMonth", ccExpirationType,
-                getString(R.string.credit_card_expiration_month_label),
-                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH);
-        mCcPartition.addLine("ccYear", View.AUTOFILL_TYPE_TEXT,
-                getString(R.string.credit_card_expiration_year_label),
-                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR);
-        mCcPartition.addLine("ccDate", ccExpirationType,
-                getString(R.string.credit_card_expiration_date_label),
-                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE);
-        mCcPartition.addLine("ccSecurityCode", View.AUTOFILL_TYPE_TEXT,
-                getString(R.string.credit_card_security_code_label),
-                "         ", true, View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE);
-
-        findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                resetFields();
-                mCustomVirtualView.resetPositions();
-                mAutofillManager.cancel();
-            }
-        });
-        mAutofillManager = getSystemService(AutofillManager.class);
-    }
-
-    private void resetFields() {
-        mCredentialsPartition.reset();
-        mCcPartition.reset();
-        mCustomVirtualView.postInvalidate();
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/NavigationItem.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/NavigationItem.java
deleted file mode 100644
index baeef68..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/NavigationItem.java
+++ /dev/null
@@ -1,78 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.ColorRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.CardView;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import com.example.android.autofillframework.R;
-
-public class NavigationItem extends FrameLayout {
-    CardView mCardView;
-
-    public NavigationItem(Context context) {
-        this(context, null);
-    }
-
-    public NavigationItem(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NavigationItem(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public NavigationItem(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NavigationItem,
-                defStyleAttr, defStyleRes);
-        String labelText = typedArray.getString(R.styleable.NavigationItem_labelText);
-        String infoText = typedArray.getString(R.styleable.NavigationItem_infoText);
-        Drawable logoDrawable = typedArray.getDrawable(R.styleable.NavigationItem_itemLogo);
-        @ColorRes int colorRes = typedArray.getResourceId(R.styleable.NavigationItem_imageColor, 0);
-        int imageColor = ContextCompat.getColor(getContext(), colorRes);
-        typedArray.recycle();
-        View rootView = LayoutInflater.from(context).inflate(R.layout.navigation_item, this);
-        if (logoDrawable != null) {
-            logoDrawable.setColorFilter(imageColor, PorterDuff.Mode.SRC_IN);
-        }
-        TextView buttonLabel = rootView.findViewById(R.id.buttonLabel);
-        buttonLabel.setText(labelText);
-        buttonLabel.setCompoundDrawablesRelativeWithIntrinsicBounds(logoDrawable, null,
-                null, null);
-        InfoButton infoButton = rootView.findViewById(R.id.infoButton);
-        infoButton.setInfoText(infoText);
-        infoButton.setColorFilter(imageColor);
-        mCardView = rootView.findViewById(R.id.cardView);
-    }
-
-    public void setNavigationButtonClickListener(@Nullable OnClickListener l) {
-        mCardView.setOnClickListener(l);
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/ScrollableCustomVirtualView.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/ScrollableCustomVirtualView.java
deleted file mode 100644
index 0ce5036..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/ScrollableCustomVirtualView.java
+++ /dev/null
@@ -1,105 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-
-/**
- * A version of {@link CustomVirtualView} that uses gesture to provide scrolling.
- */
-public class ScrollableCustomVirtualView extends CustomVirtualView
-        implements GestureDetector.OnGestureListener {
-
-    private static final String TAG = "ScrollableCustomView";
-
-    private GestureDetector mGestureDetector;
-
-    public ScrollableCustomVirtualView(Context context) {
-        this(context, null);
-    }
-
-    public ScrollableCustomVirtualView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-
-    }
-
-    public ScrollableCustomVirtualView(Context context, @Nullable AttributeSet attrs,
-            int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public ScrollableCustomVirtualView(Context context, @Nullable AttributeSet attrs,
-            int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mGestureDetector = new GestureDetector(context, this);
-    }
-
-    /**
-     * Resets the UI to the intial state.
-     */
-    public void resetPositions() {
-        super.resetCoordinates();
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        return mGestureDetector.onTouchEvent(event);
-    }
-
-    /*
-     * Methods below implement GestureDetector.OnGestureListener
-     */
-    @Override
-    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
-        if (VERBOSE) Log.v(TAG, "onScroll(): " + distanceX + " - " + distanceY);
-        if (mFocusedLine != null) {
-            mAutofillManager.notifyViewExited(this, mFocusedLine.mFieldTextItem.id);
-        }
-        mTopMargin -= distanceY;
-        mLeftMargin -= distanceX;
-        invalidate();
-        return true;
-    }
-
-    @Override
-    public boolean onDown(MotionEvent event) {
-        onMotion((int) event.getY());
-        return true;
-    }
-
-    @Override
-    public void onShowPress(MotionEvent e) {
-    }
-
-    @Override
-    public boolean onSingleTapUp(MotionEvent e) {
-        return true;
-    }
-
-    @Override
-    public void onLongPress(MotionEvent e) {
-    }
-
-    @Override
-    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardAutoCompleteSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardAutoCompleteSignInActivity.java
deleted file mode 100644
index 5fbdd34..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardAutoCompleteSignInActivity.java
+++ /dev/null
@@ -1,142 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.view.View;
-import android.view.autofill.AutofillManager;
-import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.example.android.autofillframework.R;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-public class StandardAutoCompleteSignInActivity extends AppCompatActivity {
-    private AutoCompleteTextView mUsernameAutoCompleteField;
-    private TextView mPasswordField;
-    private TextView mLoginButton;
-    private TextView mClearButton;
-    private boolean mAutofillReceived = false;
-    private AutofillManager.AutofillCallback mAutofillCallback;
-    private AutofillManager mAutofillManager;
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, StandardAutoCompleteSignInActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.login_with_autocomplete_activity);
-
-        mLoginButton = findViewById(R.id.login);
-        mClearButton = findViewById(R.id.clear);
-        mUsernameAutoCompleteField = findViewById(R.id.usernameField);
-        mPasswordField = findViewById(R.id.passwordField);
-        mLoginButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                login();
-            }
-        });
-        mClearButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                resetFields();
-            }
-        });
-        mAutofillCallback = new MyAutofillCallback();
-        mAutofillManager = getSystemService(AutofillManager.class);
-        ArrayAdapter<CharSequence> mockAutocompleteAdapter = ArrayAdapter.createFromResource
-                (this, R.array.mock_autocomplete_sign_in_suggestions,
-                        android.R.layout.simple_dropdown_item_1line);
-        mUsernameAutoCompleteField.setAdapter(mockAutocompleteAdapter);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mAutofillManager.registerCallback(mAutofillCallback);
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        mAutofillManager.unregisterCallback(mAutofillCallback);
-    }
-
-    private void resetFields() {
-        mUsernameAutoCompleteField.setText("");
-        mPasswordField.setText("");
-    }
-
-    /**
-     * Emulates a login action.
-     */
-    private void login() {
-        String username = mUsernameAutoCompleteField.getText().toString();
-        String password = mPasswordField.getText().toString();
-        boolean valid = isValidCredentials(username, password);
-        if (valid) {
-            Intent intent = WelcomeActivity.getStartActivityIntent(StandardAutoCompleteSignInActivity.this);
-            startActivity(intent);
-            finish();
-        } else {
-            Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show();
-        }
-    }
-
-    /**
-     * Dummy implementation for demo purposes. A real service should use secure mechanisms to
-     * authenticate users.
-     */
-    public boolean isValidCredentials(String username, String password) {
-        return username != null && password != null && username.equals(password);
-    }
-
-    private class MyAutofillCallback extends AutofillManager.AutofillCallback {
-        @Override
-        public void onAutofillEvent(View view, int event) {
-            super.onAutofillEvent(view, event);
-            if (view instanceof AutoCompleteTextView) {
-                switch (event) {
-                    case AutofillManager.AutofillCallback.EVENT_INPUT_UNAVAILABLE:
-                        // no break on purpose
-                    case AutofillManager.AutofillCallback.EVENT_INPUT_HIDDEN:
-                        if (!mAutofillReceived) {
-                            ((AutoCompleteTextView) view).showDropDown();
-                        }
-                        break;
-                    case AutofillManager.AutofillCallback.EVENT_INPUT_SHOWN:
-                        mAutofillReceived = true;
-                        ((AutoCompleteTextView) view).setAdapter(null);
-                        break;
-                    default:
-                        Log.d(TAG, "Unexpected callback: " + event);
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardSignInActivity.java
deleted file mode 100644
index 9038e3d..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardSignInActivity.java
+++ /dev/null
@@ -1,87 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import com.example.android.autofillframework.R;
-
-public class StandardSignInActivity extends AppCompatActivity {
-
-    private EditText mUsernameEditText;
-    private EditText mPasswordEditText;
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, StandardSignInActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.login_activity);
-        mUsernameEditText = findViewById(R.id.usernameField);
-        mPasswordEditText = findViewById(R.id.passwordField);
-        findViewById(R.id.login).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                login();
-            }
-        });
-        findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                resetFields();
-            }
-        });
-    }
-
-    private void resetFields() {
-        mUsernameEditText.setText("");
-        mPasswordEditText.setText("");
-    }
-
-    /**
-     * Emulates a login action.
-     */
-    private void login() {
-        String username = mUsernameEditText.getText().toString();
-        String password = mPasswordEditText.getText().toString();
-        boolean valid = isValidCredentials(username, password);
-        if (valid) {
-            Intent intent = WelcomeActivity.getStartActivityIntent(StandardSignInActivity.this);
-            startActivity(intent);
-            finish();
-        } else {
-            Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show();
-        }
-    }
-
-    /**
-     * Dummy implementation for demo purposes. A real service should use secure mechanisms to
-     * authenticate users.
-     */
-    public boolean isValidCredentials(String username, String password) {
-        return username != null && password != null && username.equals(password);
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/VirtualSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/VirtualSignInActivity.java
deleted file mode 100644
index 30e2539..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/VirtualSignInActivity.java
+++ /dev/null
@@ -1,105 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.autofill.AutofillManager;
-import android.widget.Toast;
-
-import com.example.android.autofillframework.R;
-
-/**
- * Activity that uses a virtual views for Username/Password text fields.
- */
-public class VirtualSignInActivity extends AppCompatActivity {
-
-    private CustomVirtualView mCustomVirtualView;
-    private AutofillManager mAutofillManager;
-    private CustomVirtualView.Line mUsernameLine;
-    private CustomVirtualView.Line mPasswordLine;
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, VirtualSignInActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.virtual_login_activity);
-
-        mCustomVirtualView = (CustomVirtualView) findViewById(R.id.custom_view);
-
-        CustomVirtualView.Partition credentialsPartition =
-                mCustomVirtualView.addPartition(getString(R.string.partition_credentials));
-        mUsernameLine = credentialsPartition.addLine("username", View.AUTOFILL_TYPE_TEXT,
-                getString(R.string.username_label),
-                "         ", false, View.AUTOFILL_HINT_USERNAME);
-        mPasswordLine = credentialsPartition.addLine("password", View.AUTOFILL_TYPE_TEXT,
-                getString(R.string.password_label),
-                "         ", true, View.AUTOFILL_HINT_PASSWORD);
-
-        findViewById(R.id.login).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                login();
-            }
-        });
-        findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                resetFields();
-                mAutofillManager.cancel();
-            }
-        });
-        mAutofillManager = getSystemService(AutofillManager.class);
-    }
-
-    private void resetFields() {
-        mUsernameLine.reset();
-        mPasswordLine.reset();
-        mCustomVirtualView.postInvalidate();
-    }
-
-    /**
-     * Emulates a login action.
-     */
-    private void login() {
-        String username = mUsernameLine.getText().toString();
-        String password = mPasswordLine.getText().toString();
-        boolean valid = isValidCredentials(username, password);
-        if (valid) {
-            Intent intent = WelcomeActivity.getStartActivityIntent(VirtualSignInActivity.this);
-            startActivity(intent);
-            finish();
-        } else {
-            Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show();
-        }
-    }
-
-    /**
-     * Dummy implementation for demo purposes. A real service should use secure mechanisms to
-     * authenticate users.
-     */
-    public boolean isValidCredentials(String username, String password) {
-        return username != null && password != null && username.equals(password);
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WebViewSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WebViewSignInActivity.java
deleted file mode 100644
index 5eb0b50..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WebViewSignInActivity.java
+++ /dev/null
@@ -1,61 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-import com.example.android.autofillframework.R;
-
-import static com.example.android.autofillframework.CommonUtil.DEBUG;
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-public class WebViewSignInActivity extends AppCompatActivity {
-
-    public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, WebViewSignInActivity.class);
-        return intent;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.login_webview_activity);
-
-        WebView webView = findViewById(R.id.webview);
-        WebSettings webSettings = webView.getSettings();
-        webView.setWebViewClient(new WebViewClient());
-        webSettings.setJavaScriptEnabled(true);
-
-        String url = getIntent().getStringExtra("url");
-        if (url == null) {
-            url = "file:///android_res/raw/sample_form.html";
-        }
-        if (DEBUG) Log.d(TAG, "Clearing WebView data");
-        webView.clearHistory();
-        webView.clearFormData();
-        webView.clearCache(true);
-        Log.i(TAG, "Loading URL " + url);
-        webView.loadUrl(url);
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.java
deleted file mode 100644
index 13eb939..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.java
+++ /dev/null
@@ -1,56 +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 com.example.android.autofillframework.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.CountDownTimer;
-import android.support.v7.app.AppCompatActivity;
-import android.widget.TextView;
-
-import com.example.android.autofillframework.R;
-
-import static java.lang.Math.toIntExact;
-
-public class WelcomeActivity extends AppCompatActivity {
-
-    public static Intent getStartActivityIntent(Context context) {
-        return new Intent(context, WelcomeActivity.class);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.welcome_activity);
-        final TextView countdownText = findViewById(R.id.countdownText);
-        new CountDownTimer(5000, 1000) {
-            @Override
-            public void onTick(long millisUntilFinished) {
-                int secondsRemaining = toIntExact(millisUntilFinished / 1000);
-                countdownText.setText(getResources().getQuantityString
-                        (R.plurals.welcome_page_countdown, secondsRemaining, secondsRemaining));
-            }
-
-            @Override
-            public void onFinish() {
-                if (!WelcomeActivity.this.isFinishing()) {
-                    finish();
-                }
-            }
-        }.start();
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AuthActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AuthActivity.java
deleted file mode 100644
index 631cc0a..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AuthActivity.java
+++ /dev/null
@@ -1,152 +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 com.example.android.autofillframework.multidatasetservice;
-
-import android.app.PendingIntent;
-import android.app.assist.AssistStructure;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.os.Bundle;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-import android.text.Editable;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsAutofillRepository;
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection;
-import com.example.android.autofillframework.multidatasetservice.settings.MyPreferences;
-
-import java.util.HashMap;
-
-import static android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE;
-import static android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT;
-import static com.example.android.autofillframework.CommonUtil.EXTRA_DATASET_NAME;
-import static com.example.android.autofillframework.CommonUtil.EXTRA_FOR_RESPONSE;
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * This Activity controls the UI for logging in to the Autofill service.
- * It is launched when an Autofill Response or specific Dataset within the Response requires
- * authentication to access. It bundles the result in an Intent.
- */
-public class AuthActivity extends AppCompatActivity {
-
-    // Unique id for dataset intents.
-    private static int sDatasetPendingIntentId = 0;
-
-    private EditText mMasterPassword;
-    private Intent mReplyIntent;
-
-    static IntentSender getAuthIntentSenderForResponse(Context context) {
-        final Intent intent = new Intent(context, AuthActivity.class);
-        return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
-                .getIntentSender();
-    }
-
-    static IntentSender getAuthIntentSenderForDataset(Context context, String datasetName) {
-        final Intent intent = new Intent(context, AuthActivity.class);
-        intent.putExtra(EXTRA_DATASET_NAME, datasetName);
-        intent.putExtra(EXTRA_FOR_RESPONSE, false);
-        return PendingIntent.getActivity(context, ++sDatasetPendingIntentId, intent,
-                PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
-    }
-
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.multidataset_service_auth_activity);
-        mMasterPassword = findViewById(R.id.master_password);
-        findViewById(R.id.login).setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                login();
-            }
-
-        });
-        findViewById(R.id.cancel).setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                onFailure();
-                AuthActivity.this.finish();
-            }
-        });
-    }
-
-    private void login() {
-        Editable password = mMasterPassword.getText();
-        if (password.toString()
-                .equals(MyPreferences.getInstance(AuthActivity.this).getMasterPassword())) {
-            onSuccess();
-        } else {
-            Toast.makeText(this, "Password incorrect", Toast.LENGTH_SHORT).show();
-            onFailure();
-        }
-        finish();
-    }
-
-    @Override
-    public void finish() {
-        if (mReplyIntent != null) {
-            setResult(RESULT_OK, mReplyIntent);
-        } else {
-            setResult(RESULT_CANCELED);
-        }
-        super.finish();
-    }
-
-    private void onFailure() {
-        Log.w(TAG, "Failed auth.");
-        mReplyIntent = null;
-    }
-
-    private void onSuccess() {
-        Intent intent = getIntent();
-        boolean forResponse = intent.getBooleanExtra(EXTRA_FOR_RESPONSE, true);
-        AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE);
-        StructureParser parser = new StructureParser(getApplicationContext(), structure);
-        parser.parseForFill();
-        AutofillFieldMetadataCollection autofillFields = parser.getAutofillFields();
-        int saveTypes = autofillFields.getSaveType();
-        mReplyIntent = new Intent();
-        HashMap<String, FilledAutofillFieldCollection> clientFormDataMap =
-                SharedPrefsAutofillRepository.getInstance().getFilledAutofillFieldCollection
-                        (this, autofillFields.getFocusedHints(), autofillFields.getAllHints());
-        if (forResponse) {
-            setResponseIntent(AutofillHelper.newResponse
-                    (this, false, autofillFields, clientFormDataMap));
-        } else {
-            String datasetName = intent.getStringExtra(EXTRA_DATASET_NAME);
-            setDatasetIntent(AutofillHelper.newDataset
-                    (this, autofillFields, clientFormDataMap.get(datasetName), false));
-        }
-    }
-
-    private void setResponseIntent(FillResponse fillResponse) {
-        mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse);
-    }
-
-    private void setDatasetIntent(Dataset dataset) {
-        mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, dataset);
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.java
deleted file mode 100644
index 1e8427d..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.java
+++ /dev/null
@@ -1,86 +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 com.example.android.autofillframework.multidatasetservice;
-
-import android.app.assist.AssistStructure.ViewNode;
-import android.view.autofill.AutofillId;
-
-import static com.example.android.autofillframework.multidatasetservice.AutofillHints.convertToStoredHintNames;
-import static com.example.android.autofillframework.multidatasetservice.AutofillHints.filterForSupportedHints;
-
-/**
- * A stripped down version of a {@link ViewNode} that contains only autofill-relevant metadata. It
- * also contains a {@code mSaveType} flag that is calculated based on the {@link ViewNode}]'s
- * autofill hints.
- */
-public class AutofillFieldMetadata {
-    private int mSaveType = 0;
-    private String[] mAutofillHints;
-    private AutofillId mAutofillId;
-    private int mAutofillType;
-    private CharSequence[] mAutofillOptions;
-    private boolean mFocused;
-
-    public AutofillFieldMetadata(ViewNode view) {
-        mAutofillId = view.getAutofillId();
-        mAutofillType = view.getAutofillType();
-        mAutofillOptions = view.getAutofillOptions();
-        mFocused = view.isFocused();
-        String[] hints = filterForSupportedHints(view.getAutofillHints());
-        if (hints != null) {
-            convertToStoredHintNames(hints);
-            setHints(hints);
-        }
-    }
-
-    public String[] getHints() {
-        return mAutofillHints;
-    }
-
-    public void setHints(String[] hints) {
-        mAutofillHints = hints;
-        mSaveType = AutofillHints.getSaveTypeForHints(hints);
-    }
-
-    public int getSaveType() {
-        return mSaveType;
-    }
-
-    public AutofillId getId() {
-        return mAutofillId;
-    }
-
-    public int getAutofillType() {
-        return mAutofillType;
-    }
-
-    /**
-     * When the {@link ViewNode} is a list that the user needs to choose a string from (i.e. a
-     * spinner), this is called to return the index of a specific item in the list.
-     */
-    public int getAutofillOptionIndex(String value) {
-        for (int i = 0; i < mAutofillOptions.length; i++) {
-            if (mAutofillOptions[i].toString().equals(value)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    public boolean isFocused() {
-        return mFocused;
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadataCollection.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadataCollection.java
deleted file mode 100644
index 59b8fcd..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadataCollection.java
+++ /dev/null
@@ -1,74 +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 com.example.android.autofillframework.multidatasetservice;
-
-import android.view.autofill.AutofillId;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Data structure that stores a collection of {@code AutofillFieldMetadata}s. Contains all of the
- * client's {@code View} hierarchy autofill-relevant metadata.
- */
-public final class AutofillFieldMetadataCollection {
-
-    private final List<AutofillId> mAutofillIds = new ArrayList<>();
-    private final HashMap<String, List<AutofillFieldMetadata>> mAutofillHintsToFieldsMap = new HashMap<>();
-    private final List<String> mAllAutofillHints = new ArrayList<>();
-    private final List<String> mFocusedAutofillHints = new ArrayList<>();
-    private int mSize = 0;
-    private int mSaveType = 0;
-
-    public void add(AutofillFieldMetadata autofillFieldMetadata) {
-        mSaveType |= autofillFieldMetadata.getSaveType();
-        mSize++;
-        mAutofillIds.add(autofillFieldMetadata.getId());
-        List<String> hintsList = Arrays.asList(autofillFieldMetadata.getHints());
-        mAllAutofillHints.addAll(hintsList);
-        if (autofillFieldMetadata.isFocused()) {
-            mFocusedAutofillHints.addAll(hintsList);
-        }
-        for (String hint : autofillFieldMetadata.getHints()) {
-            if (!mAutofillHintsToFieldsMap.containsKey(hint)) {
-                mAutofillHintsToFieldsMap.put(hint, new ArrayList<>());
-            }
-            mAutofillHintsToFieldsMap.get(hint).add(autofillFieldMetadata);
-        }
-    }
-
-    public int getSaveType() {
-        return mSaveType;
-    }
-
-    public AutofillId[] getAutofillIds() {
-        return mAutofillIds.toArray(new AutofillId[mSize]);
-    }
-
-    public List<AutofillFieldMetadata> getFieldsForHint(String hint) {
-        return mAutofillHintsToFieldsMap.get(hint);
-    }
-
-    public List<String> getFocusedHints() {
-        return mFocusedAutofillHints;
-    }
-
-    public List<String> getAllHints() {
-        return mAllAutofillHints;
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java
deleted file mode 100644
index 4c0f173..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java
+++ /dev/null
@@ -1,117 +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 com.example.android.autofillframework.multidatasetservice;
-
-import android.content.Context;
-import android.content.IntentSender;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.service.autofill.SaveInfo;
-import android.support.annotation.DrawableRes;
-import android.util.Log;
-import android.view.autofill.AutofillId;
-import android.widget.RemoteViews;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection;
-
-import java.util.HashMap;
-import java.util.Set;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * This is a class containing helper methods for building Autofill Datasets and Responses.
- */
-public final class AutofillHelper {
-
-    private AutofillHelper() {
-        throw new UnsupportedOperationException("provide static methods only");
-    }
-
-    /**
-     * Wraps autofill data in a LoginCredential  Dataset object which can then be sent back to the
-     * client View.
-     */
-    public static Dataset newDataset(Context context,
-            AutofillFieldMetadataCollection autofillFields,
-            FilledAutofillFieldCollection filledAutofillFieldCollection, boolean datasetAuth) {
-        String datasetName = filledAutofillFieldCollection.getDatasetName();
-        if (datasetName != null) {
-            Dataset.Builder datasetBuilder;
-            if (datasetAuth) {
-                datasetBuilder = new Dataset.Builder
-                        (newRemoteViews(context.getPackageName(), datasetName,
-                                R.drawable.ic_lock_black_24dp));
-                IntentSender sender =
-                        AuthActivity.getAuthIntentSenderForDataset(context, datasetName);
-                datasetBuilder.setAuthentication(sender);
-            } else {
-                datasetBuilder = new Dataset.Builder
-                        (newRemoteViews(context.getPackageName(), datasetName,
-                                R.drawable.ic_person_black_24dp));
-            }
-            boolean setValueAtLeastOnce =
-                    filledAutofillFieldCollection.applyToFields(autofillFields, datasetBuilder);
-            if (setValueAtLeastOnce) {
-                return datasetBuilder.build();
-            }
-        }
-        return null;
-    }
-
-    public static RemoteViews newRemoteViews(String packageName, String remoteViewsText,
-            @DrawableRes int drawableId) {
-        RemoteViews presentation =
-                new RemoteViews(packageName, R.layout.multidataset_service_list_item);
-        presentation.setTextViewText(R.id.text, remoteViewsText);
-        presentation.setImageViewResource(R.id.icon, drawableId);
-        return presentation;
-    }
-
-    /**
-     * Wraps autofill data in a Response object (essentially a series of Datasets) which can then
-     * be sent back to the client View.
-     */
-    public static FillResponse newResponse(Context context,
-            boolean datasetAuth, AutofillFieldMetadataCollection autofillFields,
-            HashMap<String, FilledAutofillFieldCollection> clientFormDataMap) {
-        FillResponse.Builder responseBuilder = new FillResponse.Builder();
-        if (clientFormDataMap != null) {
-            Set<String> datasetNames = clientFormDataMap.keySet();
-            for (String datasetName : datasetNames) {
-                FilledAutofillFieldCollection filledAutofillFieldCollection =
-                        clientFormDataMap.get(datasetName);
-                if (filledAutofillFieldCollection != null) {
-                    Dataset dataset = newDataset(context, autofillFields,
-                            filledAutofillFieldCollection, datasetAuth);
-                    if (dataset != null) {
-                        responseBuilder.addDataset(dataset);
-                    }
-                }
-            }
-        }
-        if (autofillFields.getSaveType() != 0) {
-            AutofillId[] autofillIds = autofillFields.getAutofillIds();
-            responseBuilder.setSaveInfo
-                    (new SaveInfo.Builder(autofillFields.getSaveType(), autofillIds).build());
-            return responseBuilder.build();
-        } else {
-            Log.d(TAG, "These fields are not meant to be saved by autofill.");
-            return null;
-        }
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHintProperties.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHintProperties.java
deleted file mode 100644
index 5a79377..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHintProperties.java
+++ /dev/null
@@ -1,86 +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 com.example.android.autofillframework.multidatasetservice;
-
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Holds the properties associated with an autofill hint in this Autofill Service.
- */
-public final class AutofillHintProperties {
-
-    private String mAutofillHint;
-    private FakeFieldGenerator mFakeFieldGenerator;
-    private Set<Integer> mValidTypes;
-    private int mSaveType;
-    private int mPartition;
-
-    public AutofillHintProperties(String autofillHint, int saveType, int partitionNumber,
-            FakeFieldGenerator fakeFieldGenerator, Integer... validTypes) {
-        mAutofillHint = autofillHint;
-        mSaveType = saveType;
-        mPartition = partitionNumber;
-        mFakeFieldGenerator = fakeFieldGenerator;
-        mValidTypes = new HashSet<>(Arrays.asList(validTypes));
-    }
-
-    /**
-     * Generates dummy autofill field data that is relevant to the autofill hint.
-     */
-    public FilledAutofillField generateFakeField(int seed) {
-        return mFakeFieldGenerator.generate(seed);
-    }
-
-    /**
-     * Returns autofill hint associated with these properties. If you save a field that uses a W3C
-     * hint, there is a chance this will return a different but analogous hint, when applicable.
-     * For example, W3C has hint 'email' and {@link android.view.View} has hint 'emailAddress', so
-     * the W3C hint should map to the hint defined in {@link android.view.View} ('emailAddress').
-     */
-    public String getAutofillHint() {
-        return mAutofillHint;
-    }
-
-    /**
-     * Returns how this hint maps to a {@link android.service.autofill.SaveInfo} type.
-     */
-    public int getSaveType() {
-        return mSaveType;
-    }
-
-    /**
-     * Returns which data partition this autofill hint should be a part of. See partitions defined
-     * in {@link AutofillHints}.
-     */
-    public int getPartition() {
-        return mPartition;
-    }
-
-
-    /**
-     * Sometimes, data for a hint should only be stored as a certain AutofillValue type. For
-     * example, it is recommended that data representing a Credit Card Expiration date, annotated
-     * with the hint {@link android.view.View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, should
-     * only be stored as {@link android.view.View.AUTOFILL_TYPE_DATE}.
-     */
-    public boolean isValidType(int type) {
-        return mValidTypes.contains(type);
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHints.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHints.java
deleted file mode 100644
index af42b10..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHints.java
+++ /dev/null
@@ -1,774 +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 com.example.android.autofillframework.multidatasetservice;
-
-import android.service.autofill.SaveInfo;
-import android.util.Log;
-import android.view.View;
-
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField;
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection;
-import com.google.common.collect.ImmutableMap;
-
-import java.util.Calendar;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-public final class AutofillHints {
-    public static final int PARTITION_OTHER = 0;
-    public static final int PARTITION_ADDRESS = 1;
-    public static final int PARTITION_EMAIL = 2;
-    public static final int PARTITION_CREDIT_CARD = 3;
-    public static final int[] PARTITIONS = {
-            PARTITION_OTHER, PARTITION_ADDRESS, PARTITION_EMAIL, PARTITION_CREDIT_CARD
-    };
-    /* TODO: finish building fake data for all hints. */
-    private static final ImmutableMap<String, AutofillHintProperties> sValidHints =
-            new ImmutableMap.Builder<String, AutofillHintProperties>()
-                    .put(View.AUTOFILL_HINT_EMAIL_ADDRESS, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_EMAIL_ADDRESS, SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS,
-                            PARTITION_EMAIL,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_EMAIL_ADDRESS);
-                                filledAutofillField.setTextValue("email" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(View.AUTOFILL_HINT_NAME, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_NAME);
-                                filledAutofillField.setTextValue("name" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(View.AUTOFILL_HINT_USERNAME, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_USERNAME, SaveInfo.SAVE_DATA_TYPE_USERNAME,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_USERNAME);
-                                filledAutofillField.setTextValue("login" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(View.AUTOFILL_HINT_PASSWORD, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_PASSWORD);
-                                filledAutofillField.setTextValue("login" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(View.AUTOFILL_HINT_PHONE, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_PHONE, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_PHONE);
-                                filledAutofillField.setTextValue("" + seed + "2345678910");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(View.AUTOFILL_HINT_POSTAL_ADDRESS, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_POSTAL_ADDRESS, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
-                            PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_POSTAL_ADDRESS);
-                                filledAutofillField.setTextValue(
-                                        "" + seed + " Fake Ln, Fake, FA, FAA 10001");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(View.AUTOFILL_HINT_POSTAL_CODE, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_POSTAL_CODE, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
-                            PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_POSTAL_CODE);
-                                filledAutofillField.setTextValue("1000" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(View.AUTOFILL_HINT_CREDIT_CARD_NUMBER, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_CREDIT_CARD_NUMBER,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
-                            PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        View.AUTOFILL_HINT_CREDIT_CARD_NUMBER);
-                                filledAutofillField.setTextValue("" + seed + "234567");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
-                            PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE);
-                                filledAutofillField.setTextValue("" + seed + seed + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE,
-                            new AutofillHintProperties(
-                                    View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE,
-                                    SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                                    (seed) -> {
-                                        FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                                View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE);
-                                        Calendar calendar = Calendar.getInstance();
-                                        calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + seed);
-                                        filledAutofillField.setDateValue(calendar.getTimeInMillis());
-                                        return filledAutofillField;
-                                    }, View.AUTOFILL_TYPE_DATE))
-                    .put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
-                            new AutofillHintProperties(
-                                    View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
-                                    SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                                    (seed) -> {
-                                        CharSequence[] months = monthRange();
-                                        int month = seed % months.length;
-                                        Calendar calendar = Calendar.getInstance();
-                                        calendar.set(Calendar.MONTH, month);
-                                        FilledAutofillField filledAutofillField =
-                                                new FilledAutofillField(
-                                                        View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH);
-                                        filledAutofillField.setListValue(months, month);
-                                        filledAutofillField.setTextValue(Integer.toString(month));
-                                        filledAutofillField.setDateValue(calendar.getTimeInMillis());
-                                        return filledAutofillField;
-                                    }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST,
-                                    View.AUTOFILL_TYPE_DATE))
-                    .put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR);
-                                Calendar calendar = Calendar.getInstance();
-                                int expYear = calendar.get(Calendar.YEAR) + seed;
-                                calendar.set(Calendar.YEAR, expYear);
-                                filledAutofillField.setDateValue(calendar.getTimeInMillis());
-                                filledAutofillField.setTextValue(Integer.toString(expYear));
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST,
-                            View.AUTOFILL_TYPE_DATE))
-                    .put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                CharSequence[] days = dayRange();
-                                int day = seed % days.length;
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY);
-                                Calendar calendar = Calendar.getInstance();
-                                calendar.set(Calendar.DATE, day);
-                                filledAutofillField.setListValue(days, day);
-                                filledAutofillField.setTextValue(Integer.toString(day));
-                                filledAutofillField.setDateValue(calendar.getTimeInMillis());
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST,
-                            View.AUTOFILL_TYPE_DATE))
-                    .put(W3cHints.HONORIFIC_PREFIX, new AutofillHintProperties(
-                            W3cHints.HONORIFIC_PREFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        W3cHints.HONORIFIC_PREFIX);
-                                CharSequence[] examplePrefixes = {"Miss", "Ms.", "Mr.", "Mx.",
-                                        "Sr.", "Dr.", "Lady", "Lord"};
-                                filledAutofillField.setListValue(examplePrefixes,
-                                        seed % examplePrefixes.length);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.GIVEN_NAME, new AutofillHintProperties(W3cHints.GIVEN_NAME,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.GIVEN_NAME);
-                                filledAutofillField.setTextValue("name" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.ADDITIONAL_NAME, new AutofillHintProperties(
-                            W3cHints.ADDITIONAL_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ADDITIONAL_NAME);
-                                filledAutofillField.setTextValue("addtlname" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.FAMILY_NAME, new AutofillHintProperties(
-                            W3cHints.FAMILY_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.FAMILY_NAME);
-                                filledAutofillField.setTextValue("famname" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.HONORIFIC_SUFFIX, new AutofillHintProperties(
-                            W3cHints.HONORIFIC_SUFFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.HONORIFIC_SUFFIX);
-                                CharSequence[] exampleSuffixes = {"san", "kun", "chan", "sama"};
-                                filledAutofillField.setListValue(exampleSuffixes,
-                                        seed % exampleSuffixes.length);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.NEW_PASSWORD, new AutofillHintProperties(
-                            W3cHints.NEW_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.NEW_PASSWORD);
-                                filledAutofillField.setTextValue("login" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.CURRENT_PASSWORD, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_PASSWORD);
-                                filledAutofillField.setTextValue("login" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.ORGANIZATION_TITLE, new AutofillHintProperties(
-                            W3cHints.ORGANIZATION_TITLE, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ORGANIZATION_TITLE);
-                                filledAutofillField.setTextValue("org" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.ORGANIZATION, new AutofillHintProperties(W3cHints.ORGANIZATION,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ORGANIZATION);
-                                filledAutofillField.setTextValue("org" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.STREET_ADDRESS, new AutofillHintProperties(
-                            W3cHints.STREET_ADDRESS, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
-                            PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.STREET_ADDRESS);
-                                filledAutofillField.setTextValue(
-                                        "" + seed + " Fake Ln, Fake, FA, FAA 10001");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.ADDRESS_LINE1, new AutofillHintProperties(W3cHints.ADDRESS_LINE1,
-                            SaveInfo.SAVE_DATA_TYPE_ADDRESS,
-                            PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ADDRESS_LINE1);
-                                filledAutofillField.setTextValue("" + seed + " Fake Ln");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.ADDRESS_LINE2, new AutofillHintProperties(W3cHints.ADDRESS_LINE2,
-                            SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ADDRESS_LINE2);
-                                filledAutofillField.setTextValue("Apt. " + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.ADDRESS_LINE3, new AutofillHintProperties(W3cHints.ADDRESS_LINE3,
-                            SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ADDRESS_LINE3);
-                                filledAutofillField.setTextValue("FA" + seed + ", FA, FAA");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.ADDRESS_LEVEL4, new AutofillHintProperties(
-                            W3cHints.ADDRESS_LEVEL4, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
-                            PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ADDRESS_LEVEL4);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.ADDRESS_LEVEL3, new AutofillHintProperties(
-                            W3cHints.ADDRESS_LEVEL3, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
-                            PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ADDRESS_LEVEL3);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.ADDRESS_LEVEL2, new AutofillHintProperties(
-                            W3cHints.ADDRESS_LEVEL2, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
-                            PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ADDRESS_LEVEL2);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.ADDRESS_LEVEL1, new AutofillHintProperties(
-                            W3cHints.ADDRESS_LEVEL1, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
-                            PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.ADDRESS_LEVEL1);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.COUNTRY, new AutofillHintProperties(W3cHints.COUNTRY,
-                            SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.COUNTRY);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.COUNTRY_NAME, new AutofillHintProperties(W3cHints.COUNTRY_NAME,
-                            SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.COUNTRY_NAME);
-                                CharSequence[] exampleCountries = {"USA", "Mexico", "Canada"};
-                                filledAutofillField.setListValue(exampleCountries,
-                                        seed % exampleCountries.length);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.POSTAL_CODE, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_POSTAL_CODE, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
-                            PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_POSTAL_CODE);
-                                filledAutofillField.setTextValue("" + seed + seed + seed + seed +
-                                        seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.CC_NAME, new AutofillHintProperties(W3cHints.CC_NAME,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
-                            PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.CC_NAME);
-                                filledAutofillField.setTextValue("firstname" + seed + "lastname" +
-                                        seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.CC_GIVEN_NAME, new AutofillHintProperties(W3cHints.CC_GIVEN_NAME,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.CC_GIVEN_NAME);
-                                filledAutofillField.setTextValue("givenname" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.CC_ADDITIONAL_NAME, new AutofillHintProperties(
-                            W3cHints.CC_ADDITIONAL_NAME, SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
-                            PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.CC_ADDITIONAL_NAME);
-                                filledAutofillField.setTextValue("addtlname" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.CC_FAMILY_NAME, new AutofillHintProperties(
-                            W3cHints.CC_FAMILY_NAME, SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
-                            PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.CC_FAMILY_NAME);
-                                filledAutofillField.setTextValue("familyname" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.CC_NUMBER, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_CREDIT_CARD_NUMBER,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        View.AUTOFILL_HINT_CREDIT_CARD_NUMBER);
-                                filledAutofillField.setTextValue("" + seed + "234567");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.CC_EXPIRATION, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE);
-                                Calendar calendar = Calendar.getInstance();
-                                calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + seed);
-                                filledAutofillField.setDateValue(calendar.getTimeInMillis());
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_DATE))
-                    .put(W3cHints.CC_EXPIRATION_MONTH, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH);
-                                CharSequence[] months = monthRange();
-                                filledAutofillField.setListValue(months,
-                                        seed % months.length);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.CC_EXPIRATION_YEAR, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR);
-                                Calendar calendar = Calendar.getInstance();
-                                int expYear = calendar.get(Calendar.YEAR) + seed;
-                                calendar.set(Calendar.YEAR, expYear);
-                                filledAutofillField.setDateValue(calendar.getTimeInMillis());
-                                filledAutofillField.setTextValue("" + expYear);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.CC_CSC, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField = new FilledAutofillField(
-                                        View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE);
-                                filledAutofillField.setTextValue("" + seed + seed + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.CC_TYPE, new AutofillHintProperties(W3cHints.CC_TYPE,
-                            SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.CC_TYPE);
-                                filledAutofillField.setTextValue("type" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.TRANSACTION_CURRENCY, new AutofillHintProperties(
-                            W3cHints.TRANSACTION_CURRENCY, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TRANSACTION_CURRENCY);
-                                CharSequence[] exampleCurrencies = {"USD", "CAD", "KYD", "CRC"};
-                                filledAutofillField.setListValue(exampleCurrencies,
-                                        seed % exampleCurrencies.length);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.TRANSACTION_AMOUNT, new AutofillHintProperties(
-                            W3cHints.TRANSACTION_AMOUNT, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TRANSACTION_AMOUNT);
-                                filledAutofillField.setTextValue("" + seed * 100);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.LANGUAGE, new AutofillHintProperties(W3cHints.LANGUAGE,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.LANGUAGE);
-                                CharSequence[] exampleLanguages = {"Bulgarian", "Croatian", "Czech",
-                                        "Danish", "Dutch", "English", "Estonian"};
-                                filledAutofillField.setListValue(exampleLanguages,
-                                        seed % exampleLanguages.length);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.BDAY, new AutofillHintProperties(W3cHints.BDAY,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.BDAY);
-                                Calendar calendar = Calendar.getInstance();
-                                calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - seed * 10);
-                                calendar.set(Calendar.MONTH, seed % 12);
-                                calendar.set(Calendar.DATE, seed % 27);
-                                filledAutofillField.setDateValue(calendar.getTimeInMillis());
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_DATE))
-                    .put(W3cHints.BDAY_DAY, new AutofillHintProperties(W3cHints.BDAY_DAY,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.BDAY_DAY);
-                                filledAutofillField.setTextValue("" + seed % 27);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.BDAY_MONTH, new AutofillHintProperties(W3cHints.BDAY_MONTH,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.BDAY_MONTH);
-                                filledAutofillField.setTextValue("" + seed % 12);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.BDAY_YEAR, new AutofillHintProperties(W3cHints.BDAY_YEAR,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.BDAY_YEAR);
-                                int year = Calendar.getInstance().get(Calendar.YEAR) - seed * 10;
-                                filledAutofillField.setTextValue("" + year);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.SEX, new AutofillHintProperties(W3cHints.SEX,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.SEX);
-                                filledAutofillField.setTextValue("Other");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.URL, new AutofillHintProperties(W3cHints.URL,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.URL);
-                                filledAutofillField.setTextValue("http://google.com");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.PHOTO, new AutofillHintProperties(W3cHints.PHOTO,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.PHOTO);
-                                filledAutofillField.setTextValue("photo" + seed + ".jpg");
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.PREFIX_SECTION, new AutofillHintProperties(
-                            W3cHints.PREFIX_SECTION, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.PREFIX_SECTION);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.SHIPPING, new AutofillHintProperties(W3cHints.SHIPPING,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.SHIPPING);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.BILLING, new AutofillHintProperties(W3cHints.BILLING,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_ADDRESS,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.BILLING);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.PREFIX_HOME, new AutofillHintProperties(W3cHints.PREFIX_HOME,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.PREFIX_HOME);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.PREFIX_WORK, new AutofillHintProperties(W3cHints.PREFIX_WORK,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.PREFIX_WORK);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.PREFIX_FAX, new AutofillHintProperties(W3cHints.PREFIX_FAX,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.PREFIX_FAX);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.PREFIX_PAGER, new AutofillHintProperties(W3cHints.PREFIX_PAGER,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.PREFIX_PAGER);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.TEL, new AutofillHintProperties(W3cHints.TEL,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TEL);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.TEL_COUNTRY_CODE, new AutofillHintProperties(
-                            W3cHints.TEL_COUNTRY_CODE, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TEL_COUNTRY_CODE);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.TEL_NATIONAL, new AutofillHintProperties(W3cHints.TEL_NATIONAL,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TEL_NATIONAL);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.TEL_AREA_CODE, new AutofillHintProperties(
-                            W3cHints.TEL_AREA_CODE, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TEL_AREA_CODE);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.TEL_LOCAL, new AutofillHintProperties(
-                            W3cHints.TEL_LOCAL, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TEL_LOCAL);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.TEL_LOCAL_PREFIX, new AutofillHintProperties(
-                            W3cHints.TEL_LOCAL_PREFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TEL_LOCAL_PREFIX);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.TEL_LOCAL_SUFFIX, new AutofillHintProperties(
-                            W3cHints.TEL_LOCAL_SUFFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TEL_LOCAL_SUFFIX);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.TEL_EXTENSION, new AutofillHintProperties(W3cHints.TEL_EXTENSION,
-                            SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.TEL_EXTENSION);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .put(W3cHints.EMAIL, new AutofillHintProperties(
-                            View.AUTOFILL_HINT_EMAIL_ADDRESS, SaveInfo.SAVE_DATA_TYPE_GENERIC,
-                            PARTITION_EMAIL,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(View.AUTOFILL_HINT_EMAIL_ADDRESS);
-                                filledAutofillField.setTextValue("email" + seed);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT))
-                    .put(W3cHints.IMPP, new AutofillHintProperties(W3cHints.IMPP,
-                            SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS, PARTITION_EMAIL,
-                            (seed) -> {
-                                FilledAutofillField filledAutofillField =
-                                        new FilledAutofillField(W3cHints.IMPP);
-                                return filledAutofillField;
-                            }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
-                    .build();
-
-    private AutofillHints() {
-    }
-
-    public static boolean isValidTypeForHints(String[] hints, int type) {
-        if (hints != null) {
-            for (String hint : hints) {
-                if (hint != null && sValidHints.containsKey(hint)) {
-                    boolean valid = sValidHints.get(hint).isValidType(type);
-                    if (valid) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
-    public static boolean isValidHint(String hint) {
-        return sValidHints.containsKey(hint);
-    }
-
-    public static int getSaveTypeForHints(String[] hints) {
-        int saveType = 0;
-        if (hints != null) {
-            for (String hint : hints) {
-                if (hint != null && sValidHints.containsKey(hint)) {
-                    saveType |= sValidHints.get(hint).getSaveType();
-                }
-            }
-        }
-        return saveType;
-    }
-
-    public static FilledAutofillField getFakeField(String hint, int seed) {
-        return sValidHints.get(hint).generateFakeField(seed);
-    }
-
-    public static FilledAutofillFieldCollection getFakeFieldCollection(int partition, int seed) {
-        FilledAutofillFieldCollection filledAutofillFieldCollection =
-                new FilledAutofillFieldCollection();
-        for (String hint : sValidHints.keySet()) {
-            if (hint != null && sValidHints.get(hint).getPartition() == partition) {
-                FilledAutofillField fakeField = getFakeField(hint, seed);
-                filledAutofillFieldCollection.add(fakeField);
-            }
-        }
-        return filledAutofillFieldCollection;
-    }
-
-    private static String getStoredHintName(String hint) {
-        return sValidHints.get(hint).getAutofillHint();
-    }
-
-    public static void convertToStoredHintNames(String[] hints) {
-        for (int i = 0; i < hints.length; i++) {
-            hints[i] = getStoredHintName(hints[i]);
-        }
-    }
-
-    private static CharSequence[] dayRange() {
-        CharSequence[] days = new CharSequence[27];
-        for (int i = 0; i < days.length; i++) {
-            days[i] = Integer.toString(i);
-        }
-        return days;
-    }
-
-    private static CharSequence[] monthRange() {
-        CharSequence[] months = new CharSequence[12];
-        for (int i = 0; i < months.length; i++) {
-            months[i] = Integer.toString(i);
-        }
-        return months;
-    }
-
-    public static String[] filterForSupportedHints(String[] hints) {
-        String[] filteredHints = new String[hints.length];
-        int i = 0;
-        for (String hint : hints) {
-            if (AutofillHints.isValidHint(hint)) {
-                filteredHints[i++] = hint;
-            } else {
-                Log.d(TAG, "Invalid autofill hint: " + hint);
-            }
-        }
-        if (i == 0) {
-            return null;
-        }
-        String[] finalFilteredHints = new String[i];
-        System.arraycopy(filteredHints, 0, finalFilteredHints, 0, i);
-        return finalFilteredHints;
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/FakeFieldGenerator.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/FakeFieldGenerator.java
deleted file mode 100644
index 383de21..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/FakeFieldGenerator.java
+++ /dev/null
@@ -1,22 +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 com.example.android.autofillframework.multidatasetservice;
-
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField;
-
-interface FakeFieldGenerator {
-    FilledAutofillField generate(int seed);
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.java
deleted file mode 100644
index ac03022..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.java
+++ /dev/null
@@ -1,144 +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 com.example.android.autofillframework.multidatasetservice;
-
-import android.app.assist.AssistStructure;
-import android.content.IntentSender;
-import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.service.autofill.AutofillService;
-import android.service.autofill.FillCallback;
-import android.service.autofill.FillContext;
-import android.service.autofill.FillRequest;
-import android.service.autofill.FillResponse;
-import android.service.autofill.SaveCallback;
-import android.service.autofill.SaveRequest;
-import android.util.Log;
-import android.view.autofill.AutofillId;
-import android.widget.RemoteViews;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsAutofillRepository;
-import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsPackageVerificationRepository;
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection;
-import com.example.android.autofillframework.multidatasetservice.settings.MyPreferences;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-import static com.example.android.autofillframework.CommonUtil.VERBOSE;
-import static com.example.android.autofillframework.CommonUtil.bundleToString;
-import static com.example.android.autofillframework.CommonUtil.dumpStructure;
-
-public class MyAutofillService extends AutofillService {
-
-    @Override
-    public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
-            FillCallback callback) {
-        AssistStructure structure = request.getFillContexts()
-                .get(request.getFillContexts().size() - 1).getStructure();
-        String packageName = structure.getActivityComponent().getPackageName();
-        if (!SharedPrefsPackageVerificationRepository.getInstance()
-                .putPackageSignatures(getApplicationContext(), packageName)) {
-            callback.onFailure(
-                    getApplicationContext().getString(R.string.invalid_package_signature));
-            return;
-        }
-        final Bundle data = request.getClientState();
-        if (VERBOSE) {
-            Log.v(TAG, "onFillRequest(): data=" + bundleToString(data));
-            dumpStructure(structure);
-        }
-
-        cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
-            @Override
-            public void onCancel() {
-                Log.w(TAG, "Cancel autofill not implemented in this sample.");
-            }
-        });
-        // Parse AutoFill data in Activity
-        StructureParser parser = new StructureParser(getApplicationContext(), structure);
-        // TODO: try / catch on other places (onSave, auth activity, etc...)
-        try {
-            parser.parseForFill();
-        } catch (SecurityException e) {
-            // TODO: handle cases where DAL didn't pass by showing a custom UI asking the user
-            // to confirm the mapping. Might require subclassing SecurityException.
-            Log.w(TAG, "Security exception handling " + request, e);
-            callback.onFailure(e.getMessage());
-            return;
-        }
-        AutofillFieldMetadataCollection autofillFields = parser.getAutofillFields();
-        FillResponse.Builder responseBuilder = new FillResponse.Builder();
-        // Check user's settings for authenticating Responses and Datasets.
-        boolean responseAuth = MyPreferences.getInstance(this).isResponseAuth();
-        AutofillId[] autofillIds = autofillFields.getAutofillIds();
-        if (responseAuth && !Arrays.asList(autofillIds).isEmpty()) {
-            // If the entire Autofill Response is authenticated, AuthActivity is used
-            // to generate Response.
-            IntentSender sender = AuthActivity.getAuthIntentSenderForResponse(this);
-            RemoteViews presentation = AutofillHelper
-                    .newRemoteViews(getPackageName(), getString(R.string.autofill_sign_in_prompt),
-                            R.drawable.ic_lock_black_24dp);
-            responseBuilder
-                    .setAuthentication(autofillIds, sender, presentation);
-            callback.onSuccess(responseBuilder.build());
-        } else {
-            boolean datasetAuth = MyPreferences.getInstance(this).isDatasetAuth();
-            HashMap<String, FilledAutofillFieldCollection> clientFormDataMap =
-                    SharedPrefsAutofillRepository.getInstance().getFilledAutofillFieldCollection(
-                            this, autofillFields.getFocusedHints(), autofillFields.getAllHints());
-            FillResponse response = AutofillHelper.newResponse
-                    (this, datasetAuth, autofillFields, clientFormDataMap);
-            callback.onSuccess(response);
-        }
-    }
-
-    @Override
-    public void onSaveRequest(SaveRequest request, SaveCallback callback) {
-        List<FillContext> context = request.getFillContexts();
-        final AssistStructure structure = context.get(context.size() - 1).getStructure();
-        String packageName = structure.getActivityComponent().getPackageName();
-        if (!SharedPrefsPackageVerificationRepository.getInstance()
-                .putPackageSignatures(getApplicationContext(), packageName)) {
-            callback.onFailure(
-                    getApplicationContext().getString(R.string.invalid_package_signature));
-            return;
-        }
-        final Bundle data = request.getClientState();
-        if (VERBOSE) {
-            Log.v(TAG, "onSaveRequest(): data=" + bundleToString(data));
-            dumpStructure(structure);
-        }
-        StructureParser parser = new StructureParser(getApplicationContext(), structure);
-        parser.parseForSave();
-        FilledAutofillFieldCollection filledAutofillFieldCollection = parser.getClientFormData();
-        SharedPrefsAutofillRepository.getInstance()
-                .saveFilledAutofillFieldCollection(this, filledAutofillFieldCollection);
-    }
-
-    @Override
-    public void onConnected() {
-        Log.d(TAG, "onConnected");
-    }
-
-    @Override
-    public void onDisconnected() {
-        Log.d(TAG, "onDisconnected");
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/SecurityHelper.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/SecurityHelper.java
deleted file mode 100644
index f18b422..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/SecurityHelper.java
+++ /dev/null
@@ -1,199 +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 com.example.android.autofillframework.multidatasetservice;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.os.AsyncTask;
-import android.util.Log;
-
-import com.google.common.net.InternetDomainName;
-
-import org.json.JSONObject;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.security.MessageDigest;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-
-import static com.example.android.autofillframework.CommonUtil.DEBUG;
-import static com.example.android.autofillframework.CommonUtil.TAG;
-import static com.example.android.autofillframework.CommonUtil.VERBOSE;
-
-/**
- * Helper class for security checks.
- */
-public final class SecurityHelper {
-
-    private static final String REST_TEMPLATE =
-            "https://digitalassetlinks.googleapis.com/v1/assetlinks:check?"
-                    + "source.web.site=%s&relation=delegate_permission/%s"
-                    + "&target.android_app.package_name=%s"
-                    + "&target.android_app.certificate.sha256_fingerprint=%s";
-
-    private static final String PERMISSION_GET_LOGIN_CREDS = "common.get_login_creds";
-    private static final String PERMISSION_HANDLE_ALL_URLS = "common.handle_all_urls";
-
-    private SecurityHelper() {
-        throw new UnsupportedOperationException("provides static methods only");
-    }
-
-    private static boolean isValidSync(String webDomain, String permission, String packageName,
-            String fingerprint) {
-        if (DEBUG) Log.d(TAG, "validating domain " + webDomain + " for pkg " + packageName
-                + " and fingerprint " + fingerprint + " for permission" + permission);
-        if (!webDomain.startsWith("http:") && !webDomain.startsWith("https:")) {
-            // Unfortunately AssistStructure.ViewNode does not tell what the domain is, so let's
-            // assume it's https
-            webDomain = "https://" + webDomain;
-        }
-
-        String restUrl =
-                String.format(REST_TEMPLATE, webDomain, permission, packageName, fingerprint);
-        if (DEBUG) Log.d(TAG, "DAL REST request: " + restUrl);
-
-        HttpURLConnection urlConnection = null;
-        StringBuilder output = new StringBuilder();
-        try {
-            URL url = new URL(restUrl);
-            urlConnection = (HttpURLConnection) url.openConnection();
-            try (BufferedReader reader = new BufferedReader(
-                    new InputStreamReader(urlConnection.getInputStream()))) {
-                String line = null;
-                while ((line = reader.readLine()) != null) {
-                    output.append(line);
-                }
-            }
-            String response = output.toString();
-            if (VERBOSE) Log.v(TAG, "DAL REST Response: " + response);
-
-            JSONObject jsonObject = new JSONObject(response);
-            boolean valid = jsonObject.optBoolean("linked", false);
-            if (DEBUG) Log.d(TAG, "Valid: " + valid);
-
-            return valid;
-        } catch (Exception e) {
-            throw new RuntimeException("Failed to validate", e);
-        } finally {
-            if (urlConnection != null) {
-                urlConnection.disconnect();
-            }
-        }
-
-    }
-
-    private static boolean isValidSync(String webDomain, String packageName, String fingerprint) {
-        boolean isValid =
-                isValidSync(webDomain, PERMISSION_GET_LOGIN_CREDS, packageName, fingerprint);
-        if (!isValid) {
-            // Ideally we should only check for the get_login_creds, but not all domains set
-            // it yet, so validating for handle_all_urls gives a higher coverage.
-            if (DEBUG) {
-                Log.d(TAG, PERMISSION_GET_LOGIN_CREDS + " validation failed; trying "
-                        + PERMISSION_HANDLE_ALL_URLS);
-            }
-            isValid = isValidSync(webDomain, PERMISSION_HANDLE_ALL_URLS, packageName, fingerprint);
-        }
-        return isValid;
-    }
-
-    public static String getCanonicalDomain(String domain) {
-        InternetDomainName idn = InternetDomainName.from(domain);
-        while (idn != null && !idn.isTopPrivateDomain()) {
-            idn = idn.parent();
-        }
-        return idn == null ? null : idn.toString();
-    }
-
-    public static boolean isValid(String webDomain, String packageName, String fingerprint) {
-        String canonicalDomain = getCanonicalDomain(webDomain);
-        if (DEBUG) Log.d(TAG, "validating domain " + canonicalDomain + " (" + webDomain
-                + ") for pkg " + packageName + " and fingerprint " + fingerprint);
-        final String fullDomain;
-        if (!webDomain.startsWith("http:") && !webDomain.startsWith("https:")) {
-            // Unfortunately AssistStructure.ViewNode does not tell what the domain is, so let's
-            // assume it's https
-            fullDomain = "https://" + canonicalDomain;
-        } else {
-            fullDomain = canonicalDomain;
-        }
-
-        // TODO: use the DAL Java API or a better REST alternative like Volley
-        // and/or document it should not block until it returns (for example, the server could
-        // start parsing the structure while it waits for the result.
-        AsyncTask<String, Integer, Boolean> task = new AsyncTask<String, Integer, Boolean>() {
-            @Override
-            protected Boolean doInBackground(String... strings) {
-                return isValidSync(fullDomain, packageName, fingerprint);
-            }
-        };
-        try {
-            return task.execute((String[]) null).get();
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            Log.w(TAG, "Thread interrupted");
-        } catch (Exception e) {
-            Log.w(TAG, "Async task failed", e);
-        }
-        return false;
-    }
-
-    /**
-     * Gets the fingerprint of the signed certificate of a package.
-     */
-    public static String getFingerprint(Context context, String packageName) throws Exception {
-        PackageManager pm = context.getPackageManager();
-        PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
-        Signature[] signatures = packageInfo.signatures;
-        if (signatures.length != 1) {
-            throw new SecurityException(packageName + " has " + signatures.length + " signatures");
-        }
-        byte[] cert = signatures[0].toByteArray();
-        try (InputStream input = new ByteArrayInputStream(cert)) {
-            CertificateFactory factory = CertificateFactory.getInstance("X509");
-            X509Certificate x509 = (X509Certificate) factory.generateCertificate(input);
-            MessageDigest md = MessageDigest.getInstance("SHA256");
-            byte[] publicKey = md.digest(x509.getEncoded());
-            return toHexFormat(publicKey);
-        }
-    }
-
-    private static String toHexFormat(byte[] bytes) {
-        StringBuilder builder = new StringBuilder(bytes.length * 2);
-        for (int i = 0; i < bytes.length; i++) {
-            String hex = Integer.toHexString(bytes[i]);
-            int length = hex.length();
-            if (length == 1) {
-                hex = "0" + hex;
-            }
-            if (length > 2) {
-                hex = hex.substring(length - 2, length);
-            }
-            builder.append(hex.toUpperCase());
-            if (i < (bytes.length - 1)) {
-                builder.append(':');
-            }
-        }
-        return builder.toString();
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java
deleted file mode 100644
index 030780f..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java
+++ /dev/null
@@ -1,138 +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 com.example.android.autofillframework.multidatasetservice;
-
-import android.app.assist.AssistStructure;
-import android.app.assist.AssistStructure.ViewNode;
-import android.app.assist.AssistStructure.WindowNode;
-import android.content.Context;
-import android.util.Log;
-import android.view.autofill.AutofillValue;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsDigitalAssetLinksRepository;
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField;
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection;
-
-import static com.example.android.autofillframework.CommonUtil.DEBUG;
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * Parser for an AssistStructure object. This is invoked when the Autofill Service receives an
- * AssistStructure from the client Activity, representing its View hierarchy. In this sample, it
- * parses the hierarchy and collects autofill metadata from {@link ViewNode}s along the way.
- */
-final class StructureParser {
-    private final AutofillFieldMetadataCollection mAutofillFields =
-            new AutofillFieldMetadataCollection();
-    private final Context mContext;
-    private final AssistStructure mStructure;
-    private FilledAutofillFieldCollection mFilledAutofillFieldCollection;
-
-    StructureParser(Context context, AssistStructure structure) {
-        mContext = context;
-        mStructure = structure;
-    }
-
-    public void parseForFill() {
-        parse(true);
-    }
-
-    public void parseForSave() {
-        parse(false);
-    }
-
-    /**
-     * Traverse AssistStructure and add ViewNode metadata to a flat list.
-     */
-    private void parse(boolean forFill) {
-        if (DEBUG) Log.d(TAG, "Parsing structure for " + mStructure.getActivityComponent());
-        int nodes = mStructure.getWindowNodeCount();
-        mFilledAutofillFieldCollection = new FilledAutofillFieldCollection();
-        StringBuilder webDomain = new StringBuilder();
-        for (int i = 0; i < nodes; i++) {
-            WindowNode node = mStructure.getWindowNodeAt(i);
-            ViewNode view = node.getRootViewNode();
-            parseLocked(forFill, view, webDomain);
-        }
-        if (webDomain.length() > 0) {
-            String packageName = mStructure.getActivityComponent().getPackageName();
-            boolean valid = SharedPrefsDigitalAssetLinksRepository.getInstance().isValid(mContext,
-                    webDomain.toString(), packageName);
-            if (!valid) {
-                throw new SecurityException(mContext.getString(
-                        R.string.invalid_link_association, webDomain, packageName));
-            }
-            if (DEBUG) Log.d(TAG, "Domain " + webDomain + " is valid for " + packageName);
-        } else {
-            if (DEBUG) Log.d(TAG, "no web domain");
-        }
-    }
-
-    private void parseLocked(boolean forFill, ViewNode viewNode, StringBuilder validWebDomain) {
-        String webDomain = viewNode.getWebDomain();
-        if (webDomain != null) {
-            if (DEBUG) Log.d(TAG, "child web domain: " + webDomain);
-            if (validWebDomain.length() > 0) {
-                if (!webDomain.equals(validWebDomain.toString())) {
-                    throw new SecurityException("Found multiple web domains: valid= "
-                            + validWebDomain + ", child=" + webDomain);
-                }
-            } else {
-                validWebDomain.append(webDomain);
-            }
-        }
-
-        if (viewNode.getAutofillHints() != null) {
-            String[] filteredHints = AutofillHints.filterForSupportedHints(
-                    viewNode.getAutofillHints());
-            if (filteredHints != null && filteredHints.length > 0) {
-                if (forFill) {
-                    mAutofillFields.add(new AutofillFieldMetadata(viewNode));
-                } else {
-                    FilledAutofillField filledAutofillField =
-                            new FilledAutofillField(viewNode.getAutofillHints());
-                    AutofillValue autofillValue = viewNode.getAutofillValue();
-                    if (autofillValue.isText()) {
-                        // Using toString of AutofillValue.getTextValue in order to save it to
-                        // SharedPreferences.
-                        filledAutofillField.setTextValue(autofillValue.getTextValue().toString());
-                    } else if (autofillValue.isDate()) {
-                        filledAutofillField.setDateValue(autofillValue.getDateValue());
-                    } else if (autofillValue.isList()) {
-                        filledAutofillField.setListValue(viewNode.getAutofillOptions(),
-                                autofillValue.getListValue());
-                    }
-                    mFilledAutofillFieldCollection.add(filledAutofillField);
-                }
-            }
-        }
-        int childrenSize = viewNode.getChildCount();
-        if (childrenSize > 0) {
-            for (int i = 0; i < childrenSize; i++) {
-                parseLocked(forFill, viewNode.getChildAt(i), validWebDomain);
-            }
-        }
-    }
-
-    public AutofillFieldMetadataCollection getAutofillFields() {
-        return mAutofillFields;
-    }
-
-    public FilledAutofillFieldCollection getClientFormData() {
-        return mFilledAutofillFieldCollection;
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.java
deleted file mode 100644
index 1408554..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.java
+++ /dev/null
@@ -1,86 +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 com.example.android.autofillframework.multidatasetservice;
-
-public final class W3cHints {
-
-    // Supported W3C autofill tokens (https://html.spec.whatwg.org/multipage/forms.html#autofill)
-    public static final String HONORIFIC_PREFIX = "honorific-prefix";
-    public static final String NAME = "name";
-    public static final String GIVEN_NAME = "given-name";
-    public static final String ADDITIONAL_NAME = "additional-name";
-    public static final String FAMILY_NAME = "family-name";
-    public static final String HONORIFIC_SUFFIX = "honorific-suffix";
-    public static final String USERNAME = "username";
-    public static final String NEW_PASSWORD = "new-password";
-    public static final String CURRENT_PASSWORD = "current-password";
-    public static final String ORGANIZATION_TITLE = "organization-title";
-    public static final String ORGANIZATION = "organization";
-    public static final String STREET_ADDRESS = "street-address";
-    public static final String ADDRESS_LINE1 = "address-line1";
-    public static final String ADDRESS_LINE2 = "address-line2";
-    public static final String ADDRESS_LINE3 = "address-line3";
-    public static final String ADDRESS_LEVEL4 = "address-level4";
-    public static final String ADDRESS_LEVEL3 = "address-level3";
-    public static final String ADDRESS_LEVEL2 = "address-level2";
-    public static final String ADDRESS_LEVEL1 = "address-level1";
-    public static final String COUNTRY = "country";
-    public static final String COUNTRY_NAME = "country-name";
-    public static final String POSTAL_CODE = "postal-code";
-    public static final String CC_NAME = "cc-name";
-    public static final String CC_GIVEN_NAME = "cc-given-name";
-    public static final String CC_ADDITIONAL_NAME = "cc-additional-name";
-    public static final String CC_FAMILY_NAME = "cc-family-name";
-    public static final String CC_NUMBER = "cc-number";
-    public static final String CC_EXPIRATION = "cc-exp";
-    public static final String CC_EXPIRATION_MONTH = "cc-exp-month";
-    public static final String CC_EXPIRATION_YEAR = "cc-exp-year";
-    public static final String CC_CSC = "cc-csc";
-    public static final String CC_TYPE = "cc-type";
-    public static final String TRANSACTION_CURRENCY = "transaction-currency";
-    public static final String TRANSACTION_AMOUNT = "transaction-amount";
-    public static final String LANGUAGE = "language";
-    public static final String BDAY = "bday";
-    public static final String BDAY_DAY = "bday-day";
-    public static final String BDAY_MONTH = "bday-month";
-    public static final String BDAY_YEAR = "bday-year";
-    public static final String SEX = "sex";
-    public static final String URL = "url";
-    public static final String PHOTO = "photo";
-    // Optional W3C prefixes
-    public static final String PREFIX_SECTION = "section-";
-    public static final String SHIPPING = "shipping";
-    public static final String BILLING = "billing";
-    // W3C prefixes below...
-    public static final String PREFIX_HOME = "home";
-    public static final String PREFIX_WORK = "work";
-    public static final String PREFIX_FAX = "fax";
-    public static final String PREFIX_PAGER = "pager";
-    // ... require those suffix
-    public static final String TEL = "tel";
-    public static final String TEL_COUNTRY_CODE = "tel-country-code";
-    public static final String TEL_NATIONAL = "tel-national";
-    public static final String TEL_AREA_CODE = "tel-area-code";
-    public static final String TEL_LOCAL = "tel-local";
-    public static final String TEL_LOCAL_PREFIX = "tel-local-prefix";
-    public static final String TEL_LOCAL_SUFFIX = "tel-local-suffix";
-    public static final String TEL_EXTENSION = "tel_extension";
-    public static final String EMAIL = "email";
-    public static final String IMPP = "impp";
-
-    private W3cHints() {
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.java
deleted file mode 100644
index b92a736..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.java
+++ /dev/null
@@ -1,44 +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 com.example.android.autofillframework.multidatasetservice.datasource;
-
-import android.content.Context;
-
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection;
-
-import java.util.HashMap;
-import java.util.List;
-
-public interface AutofillDataSource {
-
-    /**
-     * Gets saved FilledAutofillFieldCollection that contains some objects that can autofill fields
-     * with these {@code autofillHints}.
-     */
-    HashMap<String, FilledAutofillFieldCollection> getFilledAutofillFieldCollection(Context context,
-            List<String> focusedAutofillHints, List<String> allAutofillHints);
-
-    /**
-     * Stores a collection of Autofill fields.
-     */
-    void saveFilledAutofillFieldCollection(Context context,
-            FilledAutofillFieldCollection filledAutofillFieldCollection);
-
-    /**
-     * Clears all data.
-     */
-    void clear(Context context);
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/DigitalAssetLinksDataSource.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/DigitalAssetLinksDataSource.java
deleted file mode 100644
index 04624cb..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/DigitalAssetLinksDataSource.java
+++ /dev/null
@@ -1,35 +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 com.example.android.autofillframework.multidatasetservice.datasource;
-
-import android.content.Context;
-
-/**
- * Helper format
- * <a href="https://developers.google.com/digital-asset-links/">Digital Asset Links</a> needs.
- */
-public interface DigitalAssetLinksDataSource {
-
-    /**
-     * Checks if the association between a web domain and a package is valid.
-     */
-    boolean isValid(Context context, String webDomain, String packageName);
-
-    /**
-     * Clears all cached data.
-     */
-    void clear(Context context);
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/PackageVerificationDataSource.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/PackageVerificationDataSource.java
deleted file mode 100644
index 129001d..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/PackageVerificationDataSource.java
+++ /dev/null
@@ -1,38 +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 com.example.android.autofillframework.multidatasetservice.datasource;
-
-import android.content.Context;
-
-public interface PackageVerificationDataSource {
-
-    /**
-     * Verifies that the signatures in the passed {@code Context} match what is currently in
-     * storage. If there are no current signatures in storage for this packageName, it will store
-     * the signatures from the passed {@code Context}.
-     *
-     * @return {@code true} if signatures for this packageName are not currently in storage
-     * or if the signatures in the passed {@code Context} match what is currently in storage;
-     * {@code false} if the signatures in the passed {@code Context} do not match what is
-     * currently in storage or if an {@code Exception} was thrown while generating the signatures.
-     */
-    boolean putPackageSignatures(Context context, String packageName);
-
-    /**
-     * Clears all signature data currently in storage.
-     */
-    void clear(Context context);
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.java
deleted file mode 100644
index 91a1923..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.java
+++ /dev/null
@@ -1,141 +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 com.example.android.autofillframework.multidatasetservice.datasource;
-
-import android.content.Context;
-import android.util.ArraySet;
-
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Singleton autofill data repository that stores autofill fields to SharedPreferences.
- *
- * <p><b>Disclaimer</b>: you should not store sensitive fields like user data unencrypted.
- * This is done here only for simplicity and learning purposes.
- */
-public class SharedPrefsAutofillRepository implements AutofillDataSource {
-    private static final String SHARED_PREF_KEY = "com.example.android.autofillframework"
-            + ".multidatasetservice.datasource.AutofillDataSource";
-    private static final String CLIENT_FORM_DATA_KEY = "loginCredentialDatasets";
-    private static final String DATASET_NUMBER_KEY = "datasetNumber";
-    private static SharedPrefsAutofillRepository sInstance;
-
-    private SharedPrefsAutofillRepository() {
-    }
-
-    public static SharedPrefsAutofillRepository getInstance() {
-        if (sInstance == null) {
-            sInstance = new SharedPrefsAutofillRepository();
-        }
-        return sInstance;
-    }
-
-    @Override
-    public HashMap<String, FilledAutofillFieldCollection> getFilledAutofillFieldCollection(
-            Context context, List<String> focusedAutofillHints, List<String> allAutofillHints) {
-        boolean hasDataForFocusedAutofillHints = false;
-        HashMap<String, FilledAutofillFieldCollection> clientFormDataMap = new HashMap<>();
-        Set<String> clientFormDataStringSet = getAllAutofillDataStringSet(context);
-        for (String clientFormDataString : clientFormDataStringSet) {
-            Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
-            FilledAutofillFieldCollection filledAutofillFieldCollection =
-                    gson.fromJson(clientFormDataString, FilledAutofillFieldCollection.class);
-            if (filledAutofillFieldCollection != null) {
-                if (filledAutofillFieldCollection.helpsWithHints(focusedAutofillHints)) {
-                    // Saved data has data relevant to at least 1 of the hints associated with the
-                    // View in focus.
-                    hasDataForFocusedAutofillHints = true;
-                }
-                if (filledAutofillFieldCollection.helpsWithHints(allAutofillHints)) {
-                    // Saved data has data relevant to at least 1 of these hints associated with any
-                    // of the Views in the hierarchy.
-                    clientFormDataMap.put(filledAutofillFieldCollection.getDatasetName(),
-                            filledAutofillFieldCollection);
-                }
-            }
-        }
-        if (hasDataForFocusedAutofillHints) {
-            return clientFormDataMap;
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public void saveFilledAutofillFieldCollection(Context context,
-            FilledAutofillFieldCollection filledAutofillFieldCollection) {
-        String datasetName = "dataset-" + getDatasetNumber(context);
-        filledAutofillFieldCollection.setDatasetName(datasetName);
-        Set<String> allAutofillData = getAllAutofillDataStringSet(context);
-        Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
-        allAutofillData.add(gson.toJson(filledAutofillFieldCollection));
-        saveAllAutofillDataStringSet(context, allAutofillData);
-        incrementDatasetNumber(context);
-    }
-
-    @Override
-    public void clear(Context context) {
-        context.getApplicationContext()
-                .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
-                .edit()
-                .remove(CLIENT_FORM_DATA_KEY)
-                .remove(DATASET_NUMBER_KEY)
-                .apply();
-    }
-
-    private Set<String> getAllAutofillDataStringSet(Context context) {
-        return context.getApplicationContext()
-                .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
-                .getStringSet(CLIENT_FORM_DATA_KEY, new ArraySet<String>());
-    }
-
-    private void saveAllAutofillDataStringSet(Context context,
-            Set<String> allAutofillDataStringSet) {
-        context.getApplicationContext()
-                .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
-                .edit()
-                .putStringSet(CLIENT_FORM_DATA_KEY, allAutofillDataStringSet)
-                .apply();
-    }
-
-    /**
-     * For simplicity, datasets will be named in the form "dataset-X" where X means
-     * this was the Xth dataset saved.
-     */
-    private int getDatasetNumber(Context context) {
-        return context.getApplicationContext()
-                .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
-                .getInt(DATASET_NUMBER_KEY, 0);
-    }
-
-    /**
-     * Every time a dataset is saved, this should be called to increment the dataset number.
-     * (only important for this service's dataset naming scheme).
-     */
-    private void incrementDatasetNumber(Context context) {
-        context.getApplicationContext()
-                .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
-                .edit()
-                .putInt(DATASET_NUMBER_KEY, getDatasetNumber(context) + 1)
-                .apply();
-    }
-}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsDigitalAssetLinksRepository.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsDigitalAssetLinksRepository.java
deleted file mode 100644
index a8124a1..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsDigitalAssetLinksRepository.java
+++ /dev/null
@@ -1,63 +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 com.example.android.autofillframework.multidatasetservice.datasource;
-
-import android.content.Context;
-import android.util.Log;
-
-import com.example.android.autofillframework.multidatasetservice.SecurityHelper;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * Singleton repository that caches the result of Digital Asset Links checks.
- */
-public class SharedPrefsDigitalAssetLinksRepository implements DigitalAssetLinksDataSource {
-
-    private static SharedPrefsDigitalAssetLinksRepository sInstance;
-
-    private SharedPrefsDigitalAssetLinksRepository() {
-    }
-
-    public static SharedPrefsDigitalAssetLinksRepository getInstance() {
-        if (sInstance == null) {
-            sInstance = new SharedPrefsDigitalAssetLinksRepository();
-        }
-        return sInstance;
-    }
-
-    @Override
-    public boolean isValid(Context context, String webDomain, String packageName) {
-        // TODO: implement caching. It could cache the whole domain -> (packagename, fingerprint),
-        // but then either invalidate when the package change or when the DAL association times out
-        // (the maxAge is part of the API response), or document that a real-life service
-        // should do that.
-
-        String fingerprint = null;
-        try {
-            fingerprint = SecurityHelper.getFingerprint(context, packageName);
-        } catch (Exception e) {
-            Log.w(TAG, "error getting fingerprint for " + packageName, e);
-            return false;
-        }
-        return SecurityHelper.isValid(webDomain, packageName, fingerprint);
-    }
-
-    @Override
-    public void clear(Context context) {
-        // TODO: implement once if caches results or remove from the interface
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsPackageVerificationRepository.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsPackageVerificationRepository.java
deleted file mode 100644
index aa46778..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsPackageVerificationRepository.java
+++ /dev/null
@@ -1,85 +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 com.example.android.autofillframework.multidatasetservice.datasource;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-
-import com.example.android.autofillframework.multidatasetservice.SecurityHelper;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-public class SharedPrefsPackageVerificationRepository implements PackageVerificationDataSource {
-
-    private static final String SHARED_PREF_KEY = "com.example.android.autofillframework"
-            + ".multidatasetservice.datasource.PackageVerificationDataSource";
-    private static PackageVerificationDataSource sInstance;
-
-    private SharedPrefsPackageVerificationRepository() {
-    }
-
-    public static PackageVerificationDataSource getInstance() {
-        if (sInstance == null) {
-            sInstance = new SharedPrefsPackageVerificationRepository();
-        }
-        return sInstance;
-    }
-
-    @Override
-    public void clear(Context context) {
-        context.getApplicationContext().getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
-                .edit()
-                .clear()
-                .apply();
-    }
-
-    @Override
-    public boolean putPackageSignatures(Context context, String packageName) {
-        String hash;
-        try {
-            hash = SecurityHelper.getFingerprint(context, packageName);
-            Log.d(TAG, "Hash for " + packageName + ": " + hash);
-        } catch (Exception e) {
-            Log.w(TAG, "Error getting hash for " + packageName + ": " + e);
-            return false;
-        }
-
-        if (!containsSignatureForPackage(context, packageName)) {
-            // Storage does not yet contain signature for this package name.
-            context.getApplicationContext()
-                    .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
-                    .edit()
-                    .putString(packageName, hash)
-                    .apply();
-            return true;
-        }
-        return containsMatchingSignatureForPackage(context, packageName, hash);
-    }
-
-    private boolean containsSignatureForPackage(Context context, String packageName) {
-        SharedPreferences prefs = context.getApplicationContext().getSharedPreferences(
-                SHARED_PREF_KEY, Context.MODE_PRIVATE);
-        return prefs.contains(packageName);
-    }
-
-    private boolean containsMatchingSignatureForPackage(Context context, String packageName,
-            String hash) {
-        SharedPreferences prefs = context.getApplicationContext().getSharedPreferences(
-                SHARED_PREF_KEY, Context.MODE_PRIVATE);
-        return hash.equals(prefs.getString(packageName, null));
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.java
deleted file mode 100644
index dfaa1e7..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.java
+++ /dev/null
@@ -1,135 +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 com.example.android.autofillframework.multidatasetservice.model;
-
-import android.util.Log;
-import android.view.View;
-import android.view.autofill.AutofillValue;
-
-import com.example.android.autofillframework.multidatasetservice.AutofillHints;
-import com.google.common.base.Preconditions;
-import com.google.gson.annotations.Expose;
-
-import java.util.Arrays;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-import static com.example.android.autofillframework.multidatasetservice.AutofillHints.convertToStoredHintNames;
-import static com.example.android.autofillframework.multidatasetservice.AutofillHints.filterForSupportedHints;
-
-/**
- * JSON serializable data class containing the same data as an {@link AutofillValue}.
- */
-public class FilledAutofillField {
-    @Expose
-    private String mTextValue = null;
-    @Expose
-    private Long mDateValue = null;
-    @Expose
-    private Boolean mToggleValue = null;
-
-    /**
-     * Does not need to be serialized into persistent storage, so it's not exposed.
-     */
-    private String[] mAutofillHints = null;
-
-    public FilledAutofillField(String... hints) {
-        mAutofillHints = filterForSupportedHints(hints);
-        convertToStoredHintNames(mAutofillHints);
-    }
-
-    public void setListValue(CharSequence[] autofillOptions, int listValue) {
-        /* Only set list value when a hint is allowed to store list values. */
-        Preconditions.checkArgument(
-                AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_LIST),
-                "List is invalid autofill type for hint(s) - %s",
-                Arrays.toString(mAutofillHints));
-        if (autofillOptions != null && autofillOptions.length > 0) {
-            mTextValue = autofillOptions[listValue].toString();
-        } else {
-            Log.w(TAG, "autofillOptions should have at least one entry.");
-        }
-    }
-
-    public String[] getAutofillHints() {
-        return mAutofillHints;
-    }
-
-    public String getTextValue() {
-        return mTextValue;
-    }
-
-    public void setTextValue(CharSequence textValue) {
-        /* Only set text value when a hint is allowed to store text values. */
-        Preconditions.checkArgument(
-                AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_TEXT),
-                "Text is invalid autofill type for hint(s) - %s",
-                Arrays.toString(mAutofillHints));
-        mTextValue = textValue.toString();
-    }
-
-    public Long getDateValue() {
-        return mDateValue;
-    }
-
-    public void setDateValue(Long dateValue) {
-        /* Only set date value when a hint is allowed to store date values. */
-        Preconditions.checkArgument(
-                AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_DATE),
-                "Date is invalid autofill type for hint(s) - %s"
-                , Arrays.toString(mAutofillHints));
-        mDateValue = dateValue;
-    }
-
-    public Boolean getToggleValue() {
-        return mToggleValue;
-    }
-
-    public void setToggleValue(Boolean toggleValue) {
-        /* Only set toggle value when a hint is allowed to store toggle values. */
-        Preconditions.checkArgument(
-                AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_TOGGLE),
-                "Toggle is invalid autofill type for hint(s) - %s",
-                Arrays.toString(mAutofillHints));
-        mToggleValue = toggleValue;
-    }
-
-    public boolean isNull() {
-        return mTextValue == null && mDateValue == null && mToggleValue == null;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        FilledAutofillField that = (FilledAutofillField) o;
-
-        if (mTextValue != null ? !mTextValue.equals(that.mTextValue) : that.mTextValue != null)
-            return false;
-        if (mDateValue != null ? !mDateValue.equals(that.mDateValue) : that.mDateValue != null)
-            return false;
-        return mToggleValue != null ? mToggleValue.equals(that.mToggleValue) :
-                that.mToggleValue == null;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = mTextValue != null ? mTextValue.hashCode() : 0;
-        result = 31 * result + (mDateValue != null ? mDateValue.hashCode() : 0);
-        result = 31 * result + (mToggleValue != null ? mToggleValue.hashCode() : 0);
-        return result;
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java
deleted file mode 100644
index 05956ec..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java
+++ /dev/null
@@ -1,234 +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 com.example.android.autofillframework.multidatasetservice.model;
-
-import android.service.autofill.Dataset;
-import android.support.annotation.NonNull;
-import android.util.Log;
-import android.view.View;
-import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillValue;
-
-import com.example.android.autofillframework.multidatasetservice.AutofillFieldMetadata;
-import com.example.android.autofillframework.multidatasetservice.AutofillFieldMetadataCollection;
-import com.example.android.autofillframework.multidatasetservice.AutofillHints;
-import com.example.android.autofillframework.multidatasetservice.W3cHints;
-import com.google.gson.annotations.Expose;
-
-import java.util.HashMap;
-import java.util.List;
-
-import static com.example.android.autofillframework.CommonUtil.DEBUG;
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * FilledAutofillFieldCollection is the model that holds all of the data on a client app's page,
- * plus the dataset name associated with it.
- */
-public final class FilledAutofillFieldCollection {
-    @Expose
-    private final HashMap<String, FilledAutofillField> mHintMap;
-    @Expose
-    private String mDatasetName;
-
-    public FilledAutofillFieldCollection() {
-        this(null, new HashMap<String, FilledAutofillField>());
-    }
-
-    public FilledAutofillFieldCollection(String datasetName, HashMap<String, FilledAutofillField> hintMap) {
-        mHintMap = hintMap;
-        mDatasetName = datasetName;
-    }
-
-    private static boolean isW3cSectionPrefix(String hint) {
-        return hint.startsWith(W3cHints.PREFIX_SECTION);
-    }
-
-    private static boolean isW3cAddressType(String hint) {
-        switch (hint) {
-            case W3cHints.SHIPPING:
-            case W3cHints.BILLING:
-                return true;
-        }
-        return false;
-    }
-
-    private static boolean isW3cTypePrefix(String hint) {
-        switch (hint) {
-            case W3cHints.PREFIX_WORK:
-            case W3cHints.PREFIX_FAX:
-            case W3cHints.PREFIX_HOME:
-            case W3cHints.PREFIX_PAGER:
-                return true;
-        }
-        return false;
-    }
-
-    private static boolean isW3cTypeHint(String hint) {
-        switch (hint) {
-            case W3cHints.TEL:
-            case W3cHints.TEL_COUNTRY_CODE:
-            case W3cHints.TEL_NATIONAL:
-            case W3cHints.TEL_AREA_CODE:
-            case W3cHints.TEL_LOCAL:
-            case W3cHints.TEL_LOCAL_PREFIX:
-            case W3cHints.TEL_LOCAL_SUFFIX:
-            case W3cHints.TEL_EXTENSION:
-            case W3cHints.EMAIL:
-            case W3cHints.IMPP:
-                return true;
-        }
-        Log.w(TAG, "Invalid W3C type hint: " + hint);
-        return false;
-    }
-
-    /**
-     * Returns the name of the {@link Dataset}.
-     */
-    public String getDatasetName() {
-        return mDatasetName;
-    }
-
-    /**
-     * Sets the {@link Dataset} name.
-     */
-    public void setDatasetName(String datasetName) {
-        mDatasetName = datasetName;
-    }
-
-    /**
-     * Adds a {@code FilledAutofillField} to the collection, indexed by all of its hints.
-     */
-    public void add(@NonNull FilledAutofillField filledAutofillField) {
-        String[] autofillHints = filledAutofillField.getAutofillHints();
-        String nextHint = null;
-        for (int i = 0; i < autofillHints.length; i++) {
-            String hint = autofillHints[i];
-            if (i < autofillHints.length - 1) {
-                nextHint = autofillHints[i + 1];
-            }
-            // First convert the compound W3C autofill hints
-            if (isW3cSectionPrefix(hint) && i < autofillHints.length - 1) {
-                hint = autofillHints[++i];
-                if (DEBUG) Log.d(TAG, "Hint is a W3C section prefix; using " + hint + " instead");
-                if (i < autofillHints.length - 1) {
-                    nextHint = autofillHints[i + 1];
-                }
-            }
-            if (isW3cTypePrefix(hint) && nextHint != null && isW3cTypeHint(nextHint)) {
-                hint = nextHint;
-                i++;
-                if (DEBUG) Log.d(TAG, "Hint is a W3C type prefix; using " + hint + " instead");
-            }
-            if (isW3cAddressType(hint) && nextHint != null) {
-                hint = nextHint;
-                i++;
-                if (DEBUG) Log.d(TAG, "Hint is a W3C address prefix; using " + hint + " instead");
-            }
-
-            // Then check if the "actual" hint is supported.
-
-
-            if (AutofillHints.isValidHint(hint)) {
-                mHintMap.put(hint, filledAutofillField);
-            } else {
-                Log.e(TAG, "Invalid hint: " + autofillHints[i]);
-            }
-        }
-    }
-
-    /**
-     * Populates a {@link Dataset.Builder} with appropriate values for each {@link AutofillId}
-     * in a {@code AutofillFieldMetadataCollection}.
-     *
-     * In other words, it constructs an autofill
-     * {@link Dataset.Builder} by applying saved values (from this {@code FilledAutofillFieldCollection})
-     * to Views specified in a {@code AutofillFieldMetadataCollection}, which represents the current
-     * page the user is on.
-     */
-    public boolean applyToFields(AutofillFieldMetadataCollection autofillFieldMetadataCollection,
-            Dataset.Builder datasetBuilder) {
-        boolean setValueAtLeastOnce = false;
-        List<String> allHints = autofillFieldMetadataCollection.getAllHints();
-        for (int hintIndex = 0; hintIndex < allHints.size(); hintIndex++) {
-            String hint = allHints.get(hintIndex);
-            List<AutofillFieldMetadata> fillableAutofillFields =
-                    autofillFieldMetadataCollection.getFieldsForHint(hint);
-            if (fillableAutofillFields == null) {
-                continue;
-            }
-            for (int autofillFieldIndex = 0; autofillFieldIndex < fillableAutofillFields.size(); autofillFieldIndex++) {
-                FilledAutofillField filledAutofillField = mHintMap.get(hint);
-                if (filledAutofillField == null) {
-                    continue;
-                }
-                AutofillFieldMetadata autofillFieldMetadata = fillableAutofillFields.get(autofillFieldIndex);
-                AutofillId autofillId = autofillFieldMetadata.getId();
-                int autofillType = autofillFieldMetadata.getAutofillType();
-                switch (autofillType) {
-                    case View.AUTOFILL_TYPE_LIST:
-                        int listValue = autofillFieldMetadata.getAutofillOptionIndex(filledAutofillField.getTextValue());
-                        if (listValue != -1) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forList(listValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_DATE:
-                        Long dateValue = filledAutofillField.getDateValue();
-                        if (dateValue != null) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forDate(dateValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_TEXT:
-                        String textValue = filledAutofillField.getTextValue();
-                        if (textValue != null) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forText(textValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_TOGGLE:
-                        Boolean toggleValue = filledAutofillField.getToggleValue();
-                        if (toggleValue != null) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forToggle(toggleValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_NONE:
-                    default:
-                        Log.w(TAG, "Invalid autofill type - " + autofillType);
-                        break;
-                }
-            }
-        }
-        return setValueAtLeastOnce;
-    }
-
-    /**
-     * Takes in a list of autofill hints (autofillHints), usually associated with a View or set of
-     * Views. Returns whether any of the filled fields on the page have at least 1 of these
-     * autofillHints.
-     */
-    public boolean helpsWithHints(List<String> autofillHints) {
-        for (int i = 0; i < autofillHints.size(); i++) {
-            String autofillHint = autofillHints.get(i);
-            if (mHintMap.containsKey(autofillHint) && !mHintMap.get(autofillHint).isNull()) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/MyPreferences.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/MyPreferences.java
deleted file mode 100644
index 34d63ef..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/MyPreferences.java
+++ /dev/null
@@ -1,88 +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 com.example.android.autofillframework.multidatasetservice.settings;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.support.annotation.NonNull;
-
-public class MyPreferences {
-    private static final String RESPONSE_AUTH_KEY = "response_auth";
-    private static final String DATASET_AUTH_KEY = "dataset_auth";
-    private static final String MASTER_PASSWORD_KEY = "master_password";
-    private static MyPreferences sInstance;
-    private final SharedPreferences mPrefs;
-
-    private MyPreferences(Context context) {
-        mPrefs = context.getApplicationContext().getSharedPreferences("my-settings",
-                Context.MODE_PRIVATE);
-    }
-
-    public static MyPreferences getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new MyPreferences(context);
-        }
-        return sInstance;
-    }
-
-    /**
-     * Gets whether {@link FillResponse}s should require authentication.
-     */
-    public boolean isResponseAuth() {
-        return mPrefs.getBoolean(RESPONSE_AUTH_KEY, false);
-    }
-
-    /**
-     * Enables/disables authentication for the entire autofill {@link FillResponse}.
-     */
-    public void setResponseAuth(boolean responseAuth) {
-        mPrefs.edit().putBoolean(RESPONSE_AUTH_KEY, responseAuth).apply();
-    }
-
-    /**
-     * Gets whether {@link Dataset}s should require authentication.
-     */
-    public boolean isDatasetAuth() {
-        return mPrefs.getBoolean(DATASET_AUTH_KEY, false);
-    }
-
-    /**
-     * Enables/disables authentication for individual autofill {@link Dataset}s.
-     */
-    public void setDatasetAuth(boolean datasetAuth) {
-        mPrefs.edit().putBoolean(DATASET_AUTH_KEY, datasetAuth).apply();
-    }
-
-    /**
-     * Gets autofill master username.
-     */
-    public String getMasterPassword() {
-        return mPrefs.getString(MASTER_PASSWORD_KEY, null);
-    }
-
-    /**
-     * Sets autofill master password.
-     */
-    public void setMasterPassword(@NonNull String masterPassword) {
-        mPrefs.edit().putString(MASTER_PASSWORD_KEY, masterPassword).apply();
-    }
-
-    public void clearCredentials() {
-        mPrefs.edit().remove(MASTER_PASSWORD_KEY).apply();
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java
deleted file mode 100644
index 6ca5960..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java
+++ /dev/null
@@ -1,206 +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 com.example.android.autofillframework.multidatasetservice.settings;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.design.widget.Snackbar;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CompoundButton;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.NumberPicker;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.multidatasetservice.AutofillHints;
-import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsAutofillRepository;
-import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsPackageVerificationRepository;
-import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection;
-
-public class SettingsActivity extends AppCompatActivity {
-    private static final String TAG = "SettingsActivity";
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.multidataset_service_settings_activity);
-        final MyPreferences preferences = MyPreferences.getInstance(this);
-        setupSettingsSwitch(R.id.settings_auth_responses_container,
-                R.id.settings_auth_responses_label,
-                R.id.settings_auth_responses_switch,
-                preferences.isResponseAuth(),
-                (compoundButton, isResponseAuth) -> preferences.setResponseAuth(isResponseAuth));
-        setupSettingsSwitch(R.id.settings_auth_datasets_container,
-                R.id.settings_auth_datasets_label,
-                R.id.settings_auth_datasets_switch,
-                preferences.isDatasetAuth(),
-                (compoundButton, isDatasetAuth) -> preferences.setDatasetAuth(isDatasetAuth));
-        setupSettingsButton(R.id.settings_add_data_container,
-                R.id.settings_add_data_label,
-                R.id.settings_add_data_icon,
-                (view) -> buildAddDataDialog().show());
-        setupSettingsButton(R.id.settings_clear_data_container,
-                R.id.settings_clear_data_label,
-                R.id.settings_clear_data_icon,
-                (view) -> buildClearDataDialog().show());
-        setupSettingsButton(R.id.settings_auth_credentials_container,
-                R.id.settings_auth_credentials_label,
-                R.id.settings_auth_credentials_icon,
-                (view) -> {
-                    if (preferences.getMasterPassword() != null) {
-                        buildCurrentCredentialsDialog().show();
-                    } else {
-                        buildNewCredentialsDialog().show();
-                    }
-                });
-    }
-
-    private AlertDialog buildClearDataDialog() {
-        return new AlertDialog.Builder(SettingsActivity.this)
-                .setMessage(R.string.settings_clear_data_confirmation)
-                .setTitle(R.string.settings_clear_data_confirmation_title)
-                .setNegativeButton(R.string.cancel, null)
-                .setPositiveButton(R.string.ok, (dialog, which) -> {
-                    SharedPrefsAutofillRepository.getInstance().clear(SettingsActivity.this);
-                    SharedPrefsPackageVerificationRepository.getInstance()
-                            .clear(SettingsActivity.this);
-                    MyPreferences.getInstance(SettingsActivity.this).clearCredentials();
-                    dialog.dismiss();
-                })
-                .create();
-    }
-
-    private AlertDialog buildAddDataDialog() {
-        NumberPicker numberOfDatasetsPicker = LayoutInflater
-                .from(SettingsActivity.this)
-                .inflate(R.layout.multidataset_service_settings_add_data_dialog, null)
-                .findViewById(R.id.number_of_datasets_picker);
-        numberOfDatasetsPicker.setMinValue(0);
-        numberOfDatasetsPicker.setMaxValue(10);
-        numberOfDatasetsPicker.setWrapSelectorWheel(false);
-        return new AlertDialog.Builder(SettingsActivity.this)
-                .setTitle(R.string.settings_add_data_title)
-                .setNegativeButton(R.string.cancel, null)
-                .setMessage(R.string.settings_select_number_of_datasets)
-                .setView(numberOfDatasetsPicker)
-                .setPositiveButton(R.string.ok, (dialog, which) -> {
-                    int numOfDatasets = numberOfDatasetsPicker.getValue();
-                    boolean success = buildAndSaveMockedAutofillFieldCollection(
-                            SettingsActivity.this, numOfDatasets);
-                    dialog.dismiss();
-                    if (success) {
-                        Snackbar.make(SettingsActivity.this.findViewById(R.id.settings_layout),
-                                SettingsActivity.this.getResources().getQuantityString(
-                                        R.plurals.settings_add_data_success, numOfDatasets,
-                                        numOfDatasets),
-                                Snackbar.LENGTH_SHORT).show();
-                    }
-                })
-                .create();
-    }
-
-    /**
-     * Builds mock autofill data and saves it to repository.
-     */
-    private boolean buildAndSaveMockedAutofillFieldCollection(Context context, int numOfDatasets) {
-        if (numOfDatasets < 0 || numOfDatasets > 10) {
-            Log.w(TAG, "Number of Datasets out of range.");
-            return false;
-        }
-        for (int i = 0; i < numOfDatasets * 2; i += 2) {
-            for (int partition : AutofillHints.PARTITIONS) {
-                FilledAutofillFieldCollection filledAutofillFieldCollection =
-                        AutofillHints.getFakeFieldCollection(partition, i);
-                SharedPrefsAutofillRepository.getInstance().saveFilledAutofillFieldCollection(
-                        context, filledAutofillFieldCollection);
-            }
-        }
-        return true;
-    }
-
-    private AlertDialog.Builder prepareCredentialsDialog() {
-        return new AlertDialog.Builder(SettingsActivity.this)
-                .setTitle(R.string.settings_auth_change_credentials_title)
-                .setNegativeButton(R.string.cancel, null);
-    }
-
-    private AlertDialog buildCurrentCredentialsDialog() {
-        final EditText currentPasswordField = LayoutInflater
-                .from(SettingsActivity.this)
-                .inflate(R.layout.multidataset_service_settings_authentication_dialog, null)
-                .findViewById(R.id.master_password_field);
-        return prepareCredentialsDialog()
-                .setMessage(R.string.settings_auth_enter_current_password)
-                .setView(currentPasswordField)
-                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        String password = currentPasswordField.getText().toString();
-                        if (MyPreferences.getInstance(SettingsActivity.this).getMasterPassword()
-                                .equals(password)) {
-                            buildNewCredentialsDialog().show();
-                            dialog.dismiss();
-                        }
-                    }
-                })
-                .create();
-    }
-
-    private AlertDialog buildNewCredentialsDialog() {
-        final EditText newPasswordField = LayoutInflater
-                .from(SettingsActivity.this)
-                .inflate(R.layout.multidataset_service_settings_authentication_dialog, null)
-                .findViewById(R.id.master_password_field);
-        return prepareCredentialsDialog()
-                .setMessage(R.string.settings_auth_enter_new_password)
-                .setView(newPasswordField)
-                .setPositiveButton(R.string.ok, (dialog, which) -> {
-                    String password = newPasswordField.getText().toString();
-                    MyPreferences.getInstance(SettingsActivity.this).setMasterPassword(password);
-                    dialog.dismiss();
-                })
-                .create();
-    }
-
-    private void setupSettingsSwitch(int containerId, int labelId, int switchId, boolean checked,
-            CompoundButton.OnCheckedChangeListener checkedChangeListener) {
-        ViewGroup container = findViewById(containerId);
-        String switchLabel = ((TextView) container.findViewById(labelId)).getText().toString();
-        final Switch switchView = container.findViewById(switchId);
-        switchView.setContentDescription(switchLabel);
-        switchView.setChecked(checked);
-        container.setOnClickListener((view) -> switchView.performClick());
-        switchView.setOnCheckedChangeListener(checkedChangeListener);
-    }
-
-    private void setupSettingsButton(int containerId, int labelId, int imageViewId,
-            final View.OnClickListener onClickListener) {
-        ViewGroup container = findViewById(containerId);
-        TextView buttonLabel = container.findViewById(labelId);
-        String buttonLabelText = buttonLabel.getText().toString();
-        ImageView imageView = container.findViewById(imageViewId);
-        imageView.setContentDescription(buttonLabelText);
-        container.setOnClickListener(onClickListener);
-    }
-}
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_add_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_add_black_24dp.xml
deleted file mode 100644
index e50269d..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_add_black_24dp.xml
+++ /dev/null
@@ -1,24 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
-</vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_autocomplete_logo_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_autocomplete_logo_24dp.xml
index 80f30a2..18dc280 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_autocomplete_logo_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_autocomplete_logo_24dp.xml
@@ -14,11 +14,11 @@
  * limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
+        android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_custom_virtual_logo_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_custom_virtual_logo_24dp.xml
index 3a8ee3b..f230e26 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_custom_virtual_logo_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_custom_virtual_logo_24dp.xml
@@ -14,11 +14,11 @@
  * limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M13,7h-2v2h2L13,7zM13,11h-2v2h2v-2zM17,11h-2v2h2v-2zM3,3v18h18L21,3L3,3zM19,19L5,19L5,5h14v14zM13,15h-2v2h2v-2zM9,11L7,11v2h2v-2z"/>
+        android:pathData="M13,7h-2v2h2L13,7zM13,11h-2v2h2v-2zM17,11h-2v2h2v-2zM3,3v18h18L21,3L3,3zM19,19L5,19L5,5h14v14zM13,15h-2v2h2v-2zM9,11L7,11v2h2v-2z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_delete_forever_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_delete_forever_black_24dp.xml
deleted file mode 100644
index 4d2afb0..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_delete_forever_black_24dp.xml
+++ /dev/null
@@ -1,20 +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.
--->
-<vector android:alpha="0.50" android:height="24dp"
-    android:viewportHeight="24.0" android:viewportWidth="24.0"
-    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
-    <path android:fillColor="#FF000000" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/>
-</vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_disabled_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_disabled_black_24dp.xml
new file mode 100644
index 0000000..60e4cbd
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_disabled_black_24dp.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10 10,-4.5 10,-10S17.5,2 12,2zM4,12c0,-4.4 3.6,-8 8,-8 1.8,0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4,13.8 4,12zM12,20c-1.8,0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20,10.2 20,12c0,4.4 -3.6,8 -8,8z"/>
+</vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_edittexts_logo_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_edittexts_logo_24dp.xml
index 17e403d..b260df2 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_edittexts_logo_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_edittexts_logo_24dp.xml
@@ -14,11 +14,11 @@
  * limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M4,9h16v2L4,11zM4,13h10v2L4,15z"/>
+        android:pathData="M4,9h16v2L4,11zM4,13h10v2L4,15z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_email_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_email_black_24dp.xml
index 174c127..2c31d68 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_email_black_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_email_black_24dp.xml
@@ -14,11 +14,11 @@
  * limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
+        android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_info_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_info_black_24dp.xml
index c297121..a3dba1d 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_info_black_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_info_black_24dp.xml
@@ -14,11 +14,11 @@
  * limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
+        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_lock_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_lock_black_24dp.xml
deleted file mode 100644
index 6b2f014..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_lock_black_24dp.xml
+++ /dev/null
@@ -1,24 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
-</vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_person_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_person_black_24dp.xml
index 6534d9f..032db12 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_person_black_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_person_black_24dp.xml
@@ -13,8 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<vector android:alpha="0.50" android:height="24dp"
-    android:viewportHeight="24.0" android:viewportWidth="24.0"
-    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
-    <path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:alpha="0.50"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_send_white_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_send_white_24dp.xml
index f614267..5e92b26 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_send_white_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_send_white_24dp.xml
@@ -14,11 +14,11 @@
  * limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
+        android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_spinners_logo_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_spinners_logo_24dp.xml
index 5fb27a2..ea91d03 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_spinners_logo_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_spinners_logo_24dp.xml
@@ -14,11 +14,11 @@
  * limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M9,11L7,11v2h2v-2zM13,11h-2v2h2v-2zM17,11h-2v2h2v-2zM19,4h-1L18,2h-2v2L8,4L8,2L6,2v2L5,4c-1.11,0 -1.99,0.9 -1.99,2L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2zM19,20L5,20L5,9h14v11z"/>
+        android:pathData="M9,11L7,11v2h2v-2zM13,11h-2v2h2v-2zM17,11h-2v2h2v-2zM19,4h-1L18,2h-2v2L8,4L8,2L6,2v2L5,4c-1.11,0 -1.99,0.9 -1.99,2L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2zM19,20L5,20L5,9h14v11z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_view_module_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_view_module_black_24dp.xml
index ab36b07..bb739bb 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_view_module_black_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_view_module_black_24dp.xml
@@ -1,9 +1,9 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M4,11h5L9,5L4,5v6zM4,18h5v-6L4,12v6zM10,18h5v-6h-5v6zM16,18h5v-6h-5v6zM10,11h5L15,5h-5v6zM16,5v6h5L21,5h-5z"/>
+        android:pathData="M4,11h5L9,5L4,5v6zM4,18h5v-6L4,12v6zM10,18h5v-6h-5v6zM16,18h5v-6h-5v6zM10,11h5L15,5h-5v6zM16,5v6h5L21,5h-5z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_web_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_web_black_24dp.xml
index 48e7b7b..d5e35bf 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_web_black_24dp.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_web_black_24dp.xml
@@ -14,11 +14,11 @@
  * limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM15,18L4,18v-4h11v4zM15,13L4,13L4,9h11v4zM20,18h-4L16,9h4v9z"/>
+        android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM15,18L4,18v-4h11v4zM15,13L4,13L4,9h11v4zM20,18h-4L16,9h4v9z" />
 </vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/activity_main.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/activity_main.xml
index 687308e..ece13e9 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/activity_main.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/activity_main.xml
@@ -13,118 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<ScrollView
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
-    <LinearLayout
+    <android.support.design.widget.TabLayout
+        android:id="@+id/sliding_tabs"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:paddingBottom="@dimen/activity_vertical_margin"
-        android:paddingEnd="@dimen/activity_horizontal_margin"
-        android:paddingStart="@dimen/activity_horizontal_margin"
-        android:paddingTop="@dimen/activity_vertical_margin">
+        app:tabMode="fixed" />
 
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/standardViewSignInButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_red_dark"
-            app:infoText="@string/edittext_login_info"
-            app:itemLogo="@drawable/ic_edittexts_logo_24dp"
-            app:labelText="@string/navigation_button_edittext_login_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/standardLoginWithAutoCompleteButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_blue_dark"
-            app:infoText="@string/autocomplete_login_info"
-            app:itemLogo="@drawable/ic_autocomplete_logo_24dp"
-            app:labelText="@string/navigation_button_autocomplete_login_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/virtualViewSignInButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_green_dark"
-            app:infoText="@string/custom_virtual_login_info"
-            app:itemLogo="@drawable/ic_custom_virtual_logo_24dp"
-            app:labelText="@string/navigation_button_custom_virtual_view_login_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/webviewSignInButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_green_dark"
-            app:infoText="@string/webview_login_info"
-            app:itemLogo="@drawable/ic_web_black_24dp"
-            app:labelText="@string/navigation_button_web_view_login_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/creditCardSpinnersButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_orange_dark"
-            app:infoText="@string/spinners_credit_card_info"
-            app:itemLogo="@drawable/ic_spinners_logo_24dp"
-            app:labelText="@string/navigation_button_spinners_credit_card_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/creditCardCompoundViewButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_blue_light"
-            app:infoText="@string/compound_view_credit_card_info"
-            app:itemLogo="@drawable/ic_view_module_black_24dp"
-            app:labelText="@string/navigation_button_compound_view_credit_card_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/creditCardDatePickerButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_blue_light"
-            app:infoText="@string/date_picker_credit_card_info"
-            app:itemLogo="@drawable/ic_view_module_black_24dp"
-            app:labelText="@string/navigation_button_date_picker_credit_card_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/emailComposeButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_purple"
-            app:infoText="@string/email_compose_info"
-            app:itemLogo="@drawable/ic_email_black_24dp"
-            app:labelText="@string/navigation_button_email_compose_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/multiplePartitionsButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_green_dark"
-            app:infoText="@string/multiple_partitions"
-            app:itemLogo="@drawable/ic_custom_virtual_logo_24dp"
-            app:labelText="@string/navigation_button_multiple_partitions_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/creditCardButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_orange_dark"
-            app:infoText="@string/credit_card_info"
-            app:itemLogo="@drawable/ic_spinners_logo_24dp"
-            app:labelText="@string/navigation_button_credit_card_label" />
-
-        <com.example.android.autofillframework.app.NavigationItem
-            android:id="@+id/creditCardAntiPatternButton"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:imageColor="@android:color/holo_orange_dark"
-            app:infoText="@string/anti_pattern_credit_card_info"
-            app:itemLogo="@drawable/ic_spinners_logo_24dp"
-            app:labelText="@string/navigation_button_anti_pattern_credit_card_label" />
-    </LinearLayout>
-</ScrollView>
\ No newline at end of file
+    <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/pager"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</LinearLayout>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/cc_exp_date.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/cc_exp_date.xml
index a4dd537..aebe9f8 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/cc_exp_date.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/cc_exp_date.xml
@@ -14,7 +14,7 @@
  * limitations under the License.
 -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
-       xmlns:app="http://schemas.android.com/apk/res-auto">
+    xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <android.support.constraint.ConstraintLayout
         android:id="@+id/navigation_item_layout"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_activity.xml
index e2075ef..414803a 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_activity.xml
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<android.support.constraint.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/authLayout"
     android:layout_width="match_parent"
@@ -40,7 +39,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_anti_pattern_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_anti_pattern_activity.xml
index 8b9f396..9a3d4ae 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_anti_pattern_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_anti_pattern_activity.xml
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<android.support.constraint.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -37,7 +36,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/infoButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_compound_view_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_compound_view_activity.xml
index 9298704..1e00f26 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_compound_view_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_compound_view_activity.xml
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<android.support.constraint.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -38,7 +37,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -86,7 +85,7 @@
         app:layout_constraintStart_toStartOf="@id/creditCardNumberLabel"
         app:layout_constraintTop_toBottomOf="@+id/creditCardNumberLabel" />
 
-    <com.example.android.autofillframework.app.CreditCardExpirationDateCompoundView
+    <com.example.android.autofill.app.view.autofillable.CreditCardExpirationDateCompoundView
         android:id="@+id/creditCardExpirationView"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_date_picker_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_date_picker_activity.xml
index 70e3cb5..ace95d4 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_date_picker_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_date_picker_activity.xml
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<android.support.constraint.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/authLayout"
     android:layout_width="match_parent"
@@ -40,7 +39,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -89,7 +88,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/creditCardNumberLabel" />
 
-    <com.example.android.autofillframework.app.CreditCardExpirationDatePickerView
+    <com.example.android.autofill.app.view.autofillable.CreditCardExpirationDatePickerView
         android:id="@+id/creditCardExpirationView"
         android:layout_width="250dp"
         android:layout_height="wrap_content"
@@ -110,9 +109,9 @@
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/spacing_large"
         android:importantForAutofill="no"
-        android:text="@string/credit_card_security_code_label"
         android:labelFor="@+id/creditCardSecurityCode"
         android:paddingEnd="@dimen/padding_normal"
+        android:text="@string/credit_card_security_code_label"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/creditCardExpirationView" />
 
@@ -124,8 +123,8 @@
         android:layout_marginEnd="8dp"
         android:layout_marginStart="8dp"
         android:autofillHints="creditCardSecurityCode"
-        android:inputType="number"
         android:ems="6"
+        android:inputType="number"
         app:layout_constraintBottom_toBottomOf="@+id/creditCardSecurityCodeLabel"
         app:layout_constraintStart_toEndOf="@+id/creditCardSecurityCodeLabel"
         app:layout_constraintTop_toTopOf="@+id/creditCardSecurityCodeLabel" />
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_spinners_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_spinners_activity.xml
index 1034ca2..6c1bfef 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_spinners_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/credit_card_spinners_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<android.support.constraint.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -38,7 +36,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/infoButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/email_compose_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/email_compose_activity.xml
index 5df3fdc..bd1bd43 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/email_compose_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/email_compose_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<android.support.constraint.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -40,7 +38,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_common_cases.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_common_cases.xml
new file mode 100644
index 0000000..2d8078e
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_common_cases.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingBottom="@dimen/activity_vertical_margin"
+        android:paddingEnd="@dimen/activity_horizontal_margin"
+        android:paddingStart="@dimen/activity_horizontal_margin"
+        android:paddingTop="@dimen/activity_vertical_margin">
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/standardViewSignInButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_red_dark"
+            app:infoText="@string/edittext_login_info"
+            app:itemLogo="@drawable/ic_edittexts_logo_24dp"
+            app:labelText="@string/navigation_button_edittext_login_label"
+            app:destinationActivityName="com.example.android.autofill.app.commoncases.StandardSignInActivity" />
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/virtualViewSignInButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_green_dark"
+            app:infoText="@string/custom_virtual_login_info"
+            app:itemLogo="@drawable/ic_custom_virtual_logo_24dp"
+            app:labelText="@string/navigation_button_custom_virtual_view_login_label"
+            app:destinationActivityName="com.example.android.autofill.app.commoncases.VirtualSignInActivity" />
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/creditCardSpinnersButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_orange_dark"
+            app:infoText="@string/spinners_credit_card_info"
+            app:itemLogo="@drawable/ic_spinners_logo_24dp"
+            app:labelText="@string/navigation_button_spinners_credit_card_label"
+            app:destinationActivityName="com.example.android.autofill.app.commoncases.CreditCardSpinnersActivity" />
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/webviewSignInButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_purple"
+            app:infoText="@string/webview_login_info"
+            app:itemLogo="@drawable/ic_web_black_24dp"
+            app:labelText="@string/navigation_button_web_view_login_label"
+            app:destinationActivityName="com.example.android.autofill.app.commoncases.WebViewSignInActivity" />
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/creditCardCompoundViewButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_blue_light"
+            app:infoText="@string/compound_view_credit_card_info"
+            app:itemLogo="@drawable/ic_view_module_black_24dp"
+            app:labelText="@string/navigation_button_compound_view_credit_card_label"
+            app:destinationActivityName="com.example.android.autofill.app.commoncases.CreditCardCompoundViewActivity" />
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/emailComposeButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_red_dark"
+            app:infoText="@string/email_compose_info"
+            app:itemLogo="@drawable/ic_email_black_24dp"
+            app:labelText="@string/navigation_button_email_compose_label"
+            app:destinationActivityName="com.example.android.autofill.app.commoncases.EmailComposeActivity"/>
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/creditCardDatePickerButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_green_light"
+            app:infoText="@string/date_picker_credit_card_info"
+            app:itemLogo="@drawable/ic_view_module_black_24dp"
+            app:labelText="@string/navigation_button_date_picker_credit_card_label"
+            app:destinationActivityName="com.example.android.autofill.app.commoncases.CreditCardDatePickerActivity" />
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_edge_cases.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_edge_cases.xml
new file mode 100644
index 0000000..ab7c32a
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_edge_cases.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingBottom="@dimen/activity_vertical_margin"
+        android:paddingEnd="@dimen/activity_horizontal_margin"
+        android:paddingStart="@dimen/activity_horizontal_margin"
+        android:paddingTop="@dimen/activity_vertical_margin">
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/standardLoginWithAutoCompleteButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_blue_dark"
+            app:infoText="@string/autocomplete_login_info"
+            app:itemLogo="@drawable/ic_autocomplete_logo_24dp"
+            app:labelText="@string/navigation_button_autocomplete_login_label"
+            app:destinationActivityName="com.example.android.autofill.app.commoncases.StandardAutoCompleteSignInActivity"/>
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/multiplePartitionsButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_green_dark"
+            app:infoText="@string/multiple_partitions"
+            app:itemLogo="@drawable/ic_custom_virtual_logo_24dp"
+            app:labelText="@string/navigation_button_multiple_partitions_label"
+            app:destinationActivityName="com.example.android.autofill.app.edgecases.MultiplePartitionsActivity"/>
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/creditCardButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_orange_dark"
+            app:infoText="@string/credit_card_info"
+            app:itemLogo="@drawable/ic_edittexts_logo_24dp"
+            app:labelText="@string/navigation_button_credit_card_label"
+            app:destinationActivityName="com.example.android.autofill.app.edgecases.CreditCardActivity"/>
+
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/creditCardAntiPatternButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_red_dark"
+            app:infoText="@string/anti_pattern_credit_card_info"
+            app:itemLogo="@drawable/ic_disabled_black_24dp"
+            app:labelText="@string/navigation_button_anti_pattern_credit_card_label"
+            app:destinationActivityName="com.example.android.autofill.app.edgecases.CreditCardAntiPatternActivity"/>
+
+        <!--TODO finish multistep impl and show this item-->
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/multistepSignInButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_green_light"
+            app:infoText="@string/multi_step_signin_info"
+            app:itemLogo="@drawable/ic_person_black_24dp"
+            app:labelText="@string/navigation_button_multistep_signin_label"
+            app:destinationActivityName="com.example.android.autofill.app.edgecases.MultipleStepsSignInActivity"/>
+
+        <!--TODO finish multistep impl and show this item-->
+        <com.example.android.autofill.app.view.widget.NavigationItem
+            android:id="@+id/multistepCreditCardButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:imageColor="@android:color/holo_purple"
+            app:infoText="@string/multi_step_cc_info"
+            app:itemLogo="@drawable/ic_spinners_logo_24dp"
+            app:labelText="@string/navigation_button_multistep_cc_label"
+            app:destinationActivityName="com.example.android.autofill.app.edgecases.MultipleStepsCreditCardActivity"/>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/login_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/login_activity.xml
index ce70e1d..1cb4232 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/login_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/login_activity.xml
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<android.support.constraint.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/authLayout"
     android:layout_width="match_parent"
@@ -40,7 +39,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/login_webview_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/login_webview_activity.xml
index 3985f72..abbd1f4 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/login_webview_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/login_webview_activity.xml
@@ -14,6 +14,6 @@
  * limitations under the License.
 -->
 <WebView xmlns:android="http://schemas.android.com/apk/res/android"
-         android:id="@+id/webview"
-         android:layout_width="match_parent"
-         android:layout_height="match_parent" />
\ No newline at end of file
+    android:id="@+id/webview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/login_with_autocomplete_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/login_with_autocomplete_activity.xml
index 23375da..d9f89e7 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/login_with_autocomplete_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/login_with_autocomplete_activity.xml
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<android.support.constraint.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/authLayout"
     android:layout_width="match_parent"
@@ -39,7 +38,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_auth_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_auth_activity.xml
deleted file mode 100644
index 34b4424..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_auth_activity.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<android.support.constraint.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/authLayout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:importantForAutofill="noExcludeDescendants"
-    android:orientation="vertical"
-    android:paddingBottom="@dimen/activity_vertical_margin"
-    android:paddingLeft="@dimen/activity_horizontal_margin"
-    android:paddingRight="@dimen/activity_horizontal_margin"
-    android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context=".multidatasetservice.AuthActivity">
-
-    <TextView
-        android:id="@+id/master_login_header"
-        style="@style/TextAppearance.AppCompat.Large"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/spacing_normal"
-        android:text="@string/autofill_master_login_label"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-
-    <TextView
-        android:id="@+id/password_label"
-        style="@style/TextAppearance.AppCompat.Body1"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/spacing_normal"
-        android:layout_marginStart="@dimen/spacing_normal"
-        android:layout_marginTop="@dimen/spacing_large"
-        android:labelFor="@+id/master_password"
-        android:text="@string/password_label"
-        app:layout_constraintEnd_toStartOf="@+id/master_password"
-        app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/master_login_header" />
-
-    <EditText
-        android:id="@+id/master_password"
-        android:layout_width="@dimen/text_field_width"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/spacing_normal"
-        android:layout_marginStart="@dimen/spacing_normal"
-        android:layout_marginTop="@dimen/spacing_normal"
-        android:inputType="textPassword"
-        app:layout_constraintBottom_toBottomOf="@+id/password_label"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/password_label"
-        app:layout_constraintTop_toTopOf="@+id/password_label" />
-
-    <TextView
-        android:id="@+id/cancel"
-        style="@style/Widget.AppCompat.Button.Borderless"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/spacing_normal"
-        android:layout_marginTop="@dimen/spacing_normal"
-        android:text="@string/cancel"
-        android:textColor="@android:color/holo_blue_dark"
-        app:layout_constraintEnd_toStartOf="@+id/login"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/master_password" />
-
-    <TextView
-        android:id="@+id/login"
-        style="@style/Widget.AppCompat.Button.Borderless"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/spacing_normal"
-        android:layout_marginStart="@dimen/spacing_normal"
-        android:text="@string/login_label"
-        android:textColor="@android:color/holo_blue_dark"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toEndOf="@+id/cancel"
-        app:layout_constraintTop_toTopOf="@+id/cancel" />
-
-</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_list_item.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_list_item.xml
deleted file mode 100644
index ef56428..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_list_item.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@android:color/white"
-    android:orientation="horizontal">
-
-    <TextView
-        android:id="@+id/text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:gravity="center_vertical"
-        android:minHeight="?android:attr/listPreferredItemHeightSmall"
-        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-        android:textAppearance="?android:attr/textAppearanceListItemSmall" />
-
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
-        android:src="@drawable/ic_person_black_24dp" />
-</LinearLayout>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml
deleted file mode 100644
index 1618bdc..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml
+++ /dev/null
@@ -1,169 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<android.support.v4.widget.NestedScrollView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:importantForAutofill="no"
-    android:scrollbarStyle="insideOverlay"
-    android:scrollbars="vertical">
-
-    <LinearLayout
-        android:id="@+id/settings_layout"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        android:paddingBottom="@dimen/spacing_large"
-        android:paddingTop="@dimen/spacing_large">
-
-        <TextView
-            style="@style/Settings.Header"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/settings_authentication_header" />
-
-        <LinearLayout
-            android:id="@+id/settings_auth_responses_container"
-            style="@style/Settings.Container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:id="@+id/settings_auth_responses_label"
-                style="@style/Settings.Label"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:importantForAccessibility="no"
-                android:text="@string/settings_authenticate_responses" />
-
-            <Switch
-                android:id="@+id/settings_auth_responses_switch"
-                style="@style/Settings.Switch"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="@dimen/padding_normal"
-                android:minHeight="@dimen/a11y_min_touch_target_dimen" />
-
-        </LinearLayout>
-
-        <LinearLayout
-            android:id="@+id/settings_auth_datasets_container"
-            style="@style/Settings.Container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:id="@+id/settings_auth_datasets_label"
-                style="@style/Settings.Label"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:importantForAccessibility="no"
-                android:text="@string/settings_authenticate_datasets" />
-
-            <Switch
-                android:id="@+id/settings_auth_datasets_switch"
-                style="@style/Settings.Switch"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="@dimen/padding_normal"
-                android:minHeight="@dimen/a11y_min_touch_target_dimen" />
-
-        </LinearLayout>
-
-        <LinearLayout
-            android:id="@+id/settings_auth_credentials_container"
-            style="@style/Settings.Container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:id="@+id/settings_auth_credentials_label"
-                style="@style/Settings.Label"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="@string/settings_auth_credentials_label" />
-
-            <ImageView
-                android:id="@+id/settings_auth_credentials_icon"
-                style="@style/Settings.Switch"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="@dimen/padding_normal"
-                android:minHeight="@dimen/a11y_min_touch_target_dimen"
-                android:src="@drawable/ic_person_black_24dp" />
-        </LinearLayout>
-
-        <TextView
-            style="@style/Settings.Header"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:paddingTop="@dimen/spacing_normal"
-            android:text="@string/settings_data_header" />
-
-        <LinearLayout
-            android:id="@+id/settings_add_data_container"
-            style="@style/Settings.Container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:id="@+id/settings_add_data_label"
-                style="@style/Settings.Label"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="@string/settings_add_data_label" />
-
-            <ImageView
-                android:id="@+id/settings_add_data_icon"
-                style="@style/Settings.Switch"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="@dimen/padding_normal"
-                android:minHeight="@dimen/a11y_min_touch_target_dimen"
-                android:src="@drawable/ic_add_black_24dp" />
-        </LinearLayout>
-
-        <LinearLayout
-            android:id="@+id/settings_clear_data_container"
-            style="@style/Settings.Container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:id="@+id/settings_clear_data_label"
-                style="@style/Settings.Label"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="@string/settings_clear_data_label" />
-
-            <ImageView
-                android:id="@+id/settings_clear_data_icon"
-                style="@style/Settings.Switch"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="@dimen/padding_normal"
-                android:minHeight="@dimen/a11y_min_touch_target_dimen"
-                android:src="@drawable/ic_delete_forever_black_24dp" />
-        </LinearLayout>
-    </LinearLayout>
-
-</android.support.v4.widget.NestedScrollView>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml
deleted file mode 100644
index 019a367..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<NumberPicker
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/number_of_datasets_picker"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginStart="@dimen/padding_normal"
-    android:minHeight="@dimen/a11y_min_touch_target_dimen" />
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml
deleted file mode 100644
index bfd6931..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<EditText
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/master_password_field"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_margin="@dimen/spacing_normal"
-    android:importantForAutofill="no"
-    android:padding="@dimen/spacing_normal">
-
-    <requestFocus />
-</EditText>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml
index 9f6f151..e0fae46 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml
@@ -37,7 +37,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -49,19 +49,19 @@
         app:layout_constraintStart_toEndOf="@+id/multiple_partitions_header"
         app:layout_constraintTop_toTopOf="@+id/multiple_partitions_header" />
 
-    <com.example.android.autofillframework.app.ScrollableCustomVirtualView
+    <com.example.android.autofill.app.view.autofillable.ScrollableCustomVirtualView
         android:id="@+id/custom_view"
         android:layout_width="match_parent"
         android:layout_height="@dimen/multiple_partitions_height"
         android:layout_marginEnd="8dp"
         android:layout_marginStart="8dp"
-        android:paddingTop="@dimen/spacing_large"
-        android:paddingStart="@dimen/spacing_large"
         android:paddingEnd="@dimen/spacing_large"
+        android:paddingStart="@dimen/spacing_large"
+        android:paddingTop="@dimen/spacing_large"
+        app:internalTextSize="34sp"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/multiple_partitions_header"
-        app:internalTextSize="34sp"/>
+        app:layout_constraintTop_toBottomOf="@+id/multiple_partitions_header" />
 
     <TextView
         android:id="@+id/clear"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_steps_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_steps_activity.xml
new file mode 100644
index 0000000..fe7fd09
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_steps_activity.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/status"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <LinearLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="200dp"
+        android:orientation="horizontal"></LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/prev"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/previous_label" />
+
+        <Button
+            android:id="@+id/next"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/next_label" />
+
+        <Button
+            android:id="@+id/finish"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/finish_label" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/navigation_button.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/navigation_button.xml
index e4c91ec..84e27be 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/navigation_button.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/navigation_button.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +14,7 @@
  * limitations under the License.
 -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
-       xmlns:tools="http://schemas.android.com/tools">
+    xmlns:tools="http://schemas.android.com/tools">
 
     <LinearLayout
         android:id="@+id/navigation_button_layout"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/navigation_item.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/navigation_item.xml
index 9c7b3c7..200ab16 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/navigation_item.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/navigation_item.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +14,8 @@
  * limitations under the License.
 -->
 <merge 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">
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
 
     <android.support.constraint.ConstraintLayout
         android:id="@+id/navigation_item_layout"
@@ -51,7 +50,7 @@
                 tools:text="@string/navigation_button_edittext_login_label" />
         </android.support.v7.widget.CardView>
 
-        <com.example.android.autofillframework.app.InfoButton
+        <com.example.android.autofill.app.view.widget.InfoButton
             android:id="@+id/infoButton"
             android:layout_width="wrap_content"
             android:layout_height="0dp"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/virtual_login_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/virtual_login_activity.xml
index af52fb6..31ca52f 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/virtual_login_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/virtual_login_activity.xml
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<android.support.constraint.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -37,7 +36,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <com.example.android.autofillframework.app.InfoButton
+    <com.example.android.autofill.app.view.widget.InfoButton
         android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -49,15 +48,15 @@
         app:layout_constraintStart_toEndOf="@+id/custom_virtual_login_header"
         app:layout_constraintTop_toTopOf="@+id/custom_virtual_login_header" />
 
-    <com.example.android.autofillframework.app.CustomVirtualView
+    <com.example.android.autofill.app.view.autofillable.CustomVirtualView
         android:id="@+id/custom_view"
         android:layout_width="match_parent"
         android:layout_height="@dimen/custom_view_height"
-        android:paddingTop="@dimen/spacing_large"
-        android:paddingStart="@dimen/spacing_large"
-        android:paddingEnd="@dimen/spacing_large"
         android:layout_marginEnd="8dp"
         android:layout_marginStart="8dp"
+        android:paddingEnd="@dimen/spacing_large"
+        android:paddingStart="@dimen/spacing_large"
+        android:paddingTop="@dimen/spacing_large"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/custom_virtual_login_header" />
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/welcome_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/welcome_activity.xml
index 60d6e1f..a400a84 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/welcome_activity.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/welcome_activity.xml
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/raw/sample_form.html b/input/autofill/AutofillFramework/Application/src/main/res/raw/sample_form.html
index 2a26223..92596a5 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/raw/sample_form.html
+++ b/input/autofill/AutofillFramework/Application/src/main/res/raw/sample_form.html
@@ -1,5 +1,4 @@
-<!DOCTYPE html>
-<!--
+<!DOCTYPE html><!--
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,18 +14,52 @@
  * limitations under the License.
 -->
 <html>
-<body>
-<form>
-    Username: <input type='text' name='username' autocomplete='username'/><br/><br/>
-    Password: <input type='password' name='password' autocomplete='current-password'/><br/><br/>
-    Work email: <input type='text' name='email' autocomplete='work email'/><br/><br/>
-    Shipping address1: <input type='text' name='address'
-                              autocomplete='section-whatever shipping address-line1'/><br/>
-    Shipping address2: <input type='text' name='address'
-                              autocomplete='shipping address-line2'/><br/>
-    Shipping address3: <input type='text' name='address'
-                              autocomplete='section-whatever address-line3'/><br/><br/>
-    <input type='submit' value='Login'/><br/>
-</form>
-</body>
+    <body>
+        <form>
+            Username:
+            <input
+                    type='text'
+                    name='username'
+                    autocomplete='username' />
+            <br />
+            <br />
+            Password:
+            <input
+                    type='password'
+                    name='password'
+                    autocomplete='current-password' />
+            <br />
+            <br />
+            Work email:
+            <input
+                    type='text'
+                    name='email'
+                    autocomplete='work email' />
+            <br />
+            <br />
+            Shipping address1:
+            <input
+                    type='text'
+                    name='address'
+                    autocomplete='section-whatever shipping address-line1' />
+            <br />
+            Shipping address2:
+            <input
+                    type='text'
+                    name='address'
+                    autocomplete='shipping address-line2' />
+            <br />
+            Shipping address3:
+            <input
+                    type='text'
+                    name='address'
+                    autocomplete='section-whatever address-line3' />
+            <br />
+            <br />
+            <input
+                    type='submit'
+                    value='Login' />
+            <br />
+        </form>
+    </body>
 </html>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/values/attrs.xml b/input/autofill/AutofillFramework/Application/src/main/res/values/attrs.xml
index 23bf5cf..bfadd1a 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/values/attrs.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/values/attrs.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +17,7 @@
     <declare-styleable name="NavigationItem">
         <attr name="labelText" format="string" />
         <attr name="infoText" format="string" />
+        <attr name="destinationActivityName" format="string" />
         <attr name="itemLogo" format="integer" />
         <attr name="imageColor" format="reference" />
     </declare-styleable>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/values/dimens.xml b/input/autofill/AutofillFramework/Application/src/main/res/values/dimens.xml
index 43410b8..965af8a 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/values/dimens.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/values/dimens.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml b/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml
index 01a743b..2502ab7 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +16,8 @@
 
 <resources>
     <string name="app_name">Autofill Sample</string>
-    <string name="settings_name">Autofill Settings</string>
+    <string name="edge_cases_page_title">Edge Cases</string>
+    <string name="common_cases_page_title">Common Cases</string>
     <string name="navigation_button_custom_virtual_view_login_label">Sample Login Using a Custom Virtual View</string>
     <string name="navigation_button_credit_card_label">Sample Credit Card Check Out Using EditTexts</string>
     <string name="navigation_button_spinners_credit_card_label">Sample Credit Card Check Out Using Spinners</string>
@@ -29,13 +29,14 @@
     <string name="navigation_button_multiple_partitions_label">Sample Page with Multiple Data Partitions</string>
     <string name="navigation_button_web_view_login_label">Sample Login Using a WebView</string>
     <string name="navigation_button_anti_pattern_credit_card_label">Sample Credit Card Anti Pattern</string>
+    <string name="navigation_button_multistep_signin_label">Multi-Step Sign In</string>
+    <string name="navigation_button_multistep_cc_label">Multi-Step Credit Card Check Out</string>
     <string name="username_label">Username</string>
     <string name="password_label">Password</string>
     <string name="welcome_text">Success!</string>
     <string name="standard_view_sign_in">Sign in using standard views</string>
     <string name="standard_view_autocomplete_sign_in">Sign in using standard views that
         trigger AutoComplete dialogs when focused</string>
-    <string name="autofill_sign_in_prompt">Tap to sign in.</string>
     <string name="credit_card_number_label">CC Number</string>
     <string name="credit_card_expiration_label">CC Expiration</string>
     <string name="credit_card_expiration_date_label">CC Exp Date</string>
@@ -44,42 +45,16 @@
     <string name="credit_card_expiration_year_label">CC Exp Year</string>
     <string name="credit_card_security_code_label">CC Security Code</string>
     <string name="credit_card_security_code_abbrev_label">CSC</string>
-    <string name="settings_cancel">Cancel</string>
-    <string name="settings_save">Save</string>
-    <string name="settings_authenticate_responses">Authenticate responses</string>
-    <string name="settings_authenticate_datasets">Authenticate Datasets</string>
-    <string name="settings_add_data_label">Add fake Autofill data</string>
-    <string name="settings_add_data_title">Add Autofill Datasets</string>
-    <string name="settings_select_number_of_datasets">Select number of Datasets.</string>
-    <plurals name="settings_add_data_success">
-        <item quantity="one">Added %d Dataset.</item>
-        <item quantity="other">Added %d Datasets.</item>
-    </plurals>
-    <string name="settings_clear_data_label">Clear all autofill data (including credentials)</string>
-    <string name="settings_clear_data_confirmation">Are you sure you want to delete all autofill
-        data from the sample service?
-    </string>
-    <string name="settings_clear_data_confirmation_title">Confirmation</string>
     <string name="ok">OK</string>
     <string name="slash">/</string>
     <string name="cancel">Cancel</string>
-    <string name="settings_authentication_header">Authentication</string>
-    <string name="settings_data_header">Data</string>
-    <string name="settings_auth_credentials_label">Update credentials</string>
-    <string name="settings_auth_enter_current_password">Enter current password</string>
-    <string name="settings_auth_enter_new_password">Enter new password</string>
-    <string name="settings_auth_change_credentials_title">Change credentials</string>
-    <string name="settings_number_of_datasets_label">Number of Datasets</string>
     <string name="clear_label">Clear</string>
     <string name="login_label">Login</string>
     <string name="to_label">To</string>
     <string name="body_label">Body</string>
-    <string name="autofill_master_login_label">Autofill Master Login</string>
     <string name="submit_label">Submit</string>
     <string name="cc_exp_month_description">Credit Card Expiration Month</string>
     <string name="cc_exp_year_description">Credit Card Expiration Year</string>
-    <string name="invalid_package_signature">Invalid package signature</string>
-    <string name="invalid_link_association">Could not associate web domain %1$s with app %2$s</string>
     <string name="edittext_login_info">This is a sample login page that uses standard EditTexts
         from the UI toolkit. EditTexts are already optimized for autofill so extra autofill-specific
         code is almost never needed.
@@ -145,6 +120,14 @@
         activities use.
     </string>
 
+    <string name="multi_step_signin_info">
+        <!--TODO-->
+    </string>
+
+    <string name="multi_step_cc_info">
+        <!--TODO-->
+    </string>
+
     <string name="partition_credentials">Credentials</string>
     <string name="partition_credit_card">Credit Card</string>
 
@@ -155,10 +138,24 @@
     <string name="message_autofill_invalid">INVALID</string>
     <string name="message_credit_card_expiration_type">Representing expiration dates as %1$s</string>
 
+    <string name="message_finished">Finished</string>
+    <string name="message_showing_step">Showing step %1$d</string>
+    <string name="message_step_description">%1$s: %2$s</string>
+
+    <string name="previous_label">Prev</string>
+    <string name="next_label">Next</string>
+    <string name="finish_label">Finish</string>
+
     <plurals name="welcome_page_countdown">
         <item quantity="one">Automatically return to main page in %d second.</item>
         <item quantity="other">Automatically return to main page in %d seconds.</item>
     </plurals>
+
+    <string-array name="mock_autocomplete_sign_in_suggestions">
+        <item>user-1</item>
+        <item>user-2</item>
+    </string-array>
+
     <string-array name="month_array">
         <item>1</item>
         <item>2</item>
@@ -204,9 +201,4 @@
         <item>27</item>
     </string-array>
 
-    <string-array name="mock_autocomplete_sign_in_suggestions">
-        <item>user-1</item>
-        <item>user-2</item>
-    </string-array>
-
 </resources>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/values/styles.xml b/input/autofill/AutofillFramework/Application/src/main/res/values/styles.xml
index c44f999..39e5ba8 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/values/styles.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/values/styles.xml
@@ -15,33 +15,6 @@
 -->
 <resources>
 
-    <style name="Settings.Label" parent="">
-        <item name="android:ellipsize">end</item>
-        <item name="android:lines">1</item>
-        <item name="android:paddingBottom">@dimen/spacing_normal</item>
-        <item name="android:paddingTop">@dimen/spacing_normal</item>
-    </style>
-
-    <style name="Settings.Container" parent="">
-        <item name="android:background">?android:selectableItemBackground</item>
-        <item name="android:gravity">center_vertical</item>
-        <item name="android:minHeight">?android:listPreferredItemHeightSmall</item>
-        <item name="android:orientation">horizontal</item>
-        <item name="android:paddingEnd">?android:listPreferredItemPaddingEnd</item>
-        <item name="android:paddingStart">?android:listPreferredItemPaddingStart</item>
-    </style>
-
-    <style name="Settings.Switch" parent="">
-        <!-- We make the parent view clickable instead for better touch feedback -->
-        <item name="android:background">@null</item>
-        <item name="android:clickable">false</item>
-    </style>
-
-    <style name="Settings.Header" parent="@style/TextAppearance.AppCompat.Large">
-        <item name="android:paddingStart">?android:listPreferredItemPaddingStart</item>
-        <item name="android:paddingBottom">@dimen/spacing_normal</item>
-    </style>
-
     <style name="CustomDatePickerDialogTheme" parent="android:Theme.Material.Light.Dialog">
         <item name="android:datePickerStyle">@style/MyDatePickerStyle</item>
     </style>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/xml/multidataset_service.xml b/input/autofill/AutofillFramework/Application/src/main/res/xml/multidataset_service.xml
deleted file mode 100644
index 0c1c14d..0000000
--- a/input/autofill/AutofillFramework/Application/src/main/res/xml/multidataset_service.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-
-<!--
-Attributes for the AutoFill service that tell the framework what will act as the Autofill service's
-Settings Activity. This is pointed to in the service's meta-data in the application's manifest.
--->
-<autofill-service
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:settingsActivity="com.example.android.autofillframework.multidatasetservice.settings.SettingsActivity"/>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/.gitignore b/input/autofill/AutofillFramework/afservice/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/input/autofill/AutofillFramework/afservice/build.gradle b/input/autofill/AutofillFramework/afservice/build.gradle
new file mode 100644
index 0000000..f614207
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/build.gradle
@@ -0,0 +1,51 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion "android-P"
+
+    defaultConfig {
+        minSdkVersion 26
+        targetSdkVersion 28
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled true
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+        debug {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+dependencies {
+    implementation 'com.android.support:appcompat-v7:28.0.0-alpha1'
+    implementation "android.arch.persistence.room:runtime:1.0.0"
+    annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'com.android.support:design:28.0.0-alpha1'
+    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
+    implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.2'
+    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
+    implementation group: 'com.google.guava', name: 'guava', version: '22.0-android'
+    implementation "com.android.support.test.espresso:espresso-idling-resource:3.0.1"
+    implementation "com.google.code.findbugs:jsr305:3.0.2"
+
+    androidTestImplementation "junit:junit:4.12"
+    androidTestImplementation ("com.android.support.test.espresso:espresso-core:3.0.1")
+    androidTestImplementation "com.android.support.test.espresso:espresso-contrib:3.0.1"
+    androidTestImplementation "com.android.support.test.espresso:espresso-intents:3.0.1"
+    androidTestImplementation "com.android.support.test.espresso.idling:idling-concurrent:3.0.1"
+
+}
diff --git a/input/autofill/AutofillFramework/afservice/proguard-rules.pro b/input/autofill/AutofillFramework/afservice/proguard-rules.pro
new file mode 100644
index 0000000..a313042
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/proguard-rules.pro
@@ -0,0 +1,24 @@
+# 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
+-keep class com.google.common.base.Preconditions { *; }
+-keep class android.arch.** { *; }
+-keep com.example.android.autofill.service.** { *; }
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/AutofillDaoTest.java b/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/AutofillDaoTest.java
new file mode 100644
index 0000000..c76ba43
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/AutofillDaoTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 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 com.example.android.autofill.service.data.source.local;
+
+import android.arch.persistence.room.Room;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import com.example.android.autofill.service.data.source.local.db.AutofillDatabase;
+import com.example.android.autofill.service.model.AutofillDataset;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FilledAutofillField;
+import com.google.common.collect.ImmutableList;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.UUID;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.hasSize;
+
+@RunWith(AndroidJUnit4.class)
+public class AutofillDaoTest {
+    private final AutofillDataset mDataset =
+            new AutofillDataset(UUID.randomUUID().toString(),
+                    "dataset-1", InstrumentationRegistry.getContext().getPackageName());
+    private final FilledAutofillField mUsernameField =
+            new FilledAutofillField(mDataset.getId(), View.AUTOFILL_HINT_USERNAME, "login");
+    private final FilledAutofillField mPasswordField =
+            new FilledAutofillField(mDataset.getId(), View.AUTOFILL_HINT_PASSWORD, "password");
+
+    private AutofillDatabase mDatabase;
+
+    @Before
+    public void setup() {
+        // using an in-memory database because the information stored here disappears when the
+        // process is killed
+        mDatabase = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getContext(),
+                AutofillDatabase.class).build();
+
+    }
+
+    @After
+    public void closeDb() {
+        mDatabase.close();
+    }
+
+    @Test
+    public void insertFilledAutofillFieldAndGet() {
+        DatasetWithFilledAutofillFields datasetWithFilledAutofillFields =
+                new DatasetWithFilledAutofillFields();
+        datasetWithFilledAutofillFields.autofillDataset = mDataset;
+        datasetWithFilledAutofillFields.filledAutofillFields =
+                Arrays.asList(mUsernameField, mPasswordField);
+        datasetWithFilledAutofillFields.filledAutofillFields
+                .sort(Comparator.comparing(FilledAutofillField::getFieldTypeName));
+
+        // When inserting a page's autofill fields.
+        mDatabase.autofillDao().insertAutofillDataset(mDataset);
+        mDatabase.autofillDao().insertFilledAutofillFields(
+                datasetWithFilledAutofillFields.filledAutofillFields);
+
+        // Represents all hints of all fields on page.
+        List<String> allHints = ImmutableList.of(View.AUTOFILL_HINT_USERNAME,
+                View.AUTOFILL_HINT_PASSWORD);
+        List<DatasetWithFilledAutofillFields> loadedDatasets = mDatabase.autofillDao()
+                .getDatasets(allHints);
+        loadedDatasets.get(0).filledAutofillFields.sort(
+                Comparator.comparing(FilledAutofillField::getFieldTypeName));
+        assertThat(loadedDatasets, contains(datasetWithFilledAutofillFields));
+        assertThat(loadedDatasets, hasSize(1));
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/LocalDataSourceTest.java b/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/LocalDataSourceTest.java
new file mode 100644
index 0000000..2f445c5
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/LocalDataSourceTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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 com.example.android.autofill.service.data.source.local;
+
+import android.arch.persistence.room.Room;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.example.android.autofill.service.data.source.local.dao.AutofillDao;
+import com.example.android.autofill.service.data.source.local.db.AutofillDatabase;
+import com.example.android.autofill.service.util.SingleExecutors;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class LocalDataSourceTest {
+
+    private LocalAutofillDataSource mLocalDataSource;
+    private AutofillDatabase mDatabase;
+
+    @Before
+    public void setup() {
+        // using an in-memory database for testing, since it doesn't survive killing the process
+        mDatabase = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getContext(),
+                AutofillDatabase.class)
+                .build();
+        AutofillDao tasksDao = mDatabase.autofillDao();
+        SharedPreferences sharedPreferences = InstrumentationRegistry.getContext()
+                .getSharedPreferences(LocalAutofillDataSource.SHARED_PREF_KEY, Context.MODE_PRIVATE);
+        // Make sure that we're not keeping a reference to the wrong instance.
+        LocalAutofillDataSource.clearInstance();
+        mLocalDataSource = LocalAutofillDataSource.getInstance(sharedPreferences,
+                tasksDao, new SingleExecutors());
+    }
+
+    @After
+    public void cleanUp() {
+        try {
+            mDatabase.close();
+        } finally {
+            LocalAutofillDataSource.clearInstance();
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/util/SingleExecutors.java b/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/util/SingleExecutors.java
new file mode 100644
index 0000000..baac2b1
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/util/SingleExecutors.java
@@ -0,0 +1,30 @@
+/*
+ * 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 com.example.android.autofill.service.util;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Allow instant execution of tasks.
+ */
+public final class SingleExecutors extends AppExecutors {
+    private static Executor sInstance = Runnable::run;
+
+    public SingleExecutors() {
+        super(sInstance, sInstance, sInstance);
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/AndroidManifest.xml b/input/autofill/AutofillFramework/afservice/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b02a591
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/AndroidManifest.xml
@@ -0,0 +1,77 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.autofill.service">
+
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <!--
+    Declare AutofillService implementation; only needed for a small number of apps that will
+    be implementing an AutofillService. Framework parses meta-data and sets the service's
+    Settings Activity based on what the meta-data resource points to.
+    -->
+        <service
+            android:name=".MyAutofillService"
+            android:label="Multi-Dataset Autofill Service"
+            android:permission="android.permission.BIND_AUTOFILL_SERVICE">
+            <meta-data
+                android:name="android.autofill"
+                android:resource="@xml/multidataset_service" />
+
+            <intent-filter>
+                <action android:name="android.service.autofill.AutofillService" />
+            </intent-filter>
+        </service>
+
+        <service
+            android:name=".simple.BasicService"
+            android:label="Basic Autofill Service"
+            android:permission="android.permission.BIND_AUTOFILL_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.autofill.AutofillService" />
+            </intent-filter>
+        </service>
+
+        <service
+            android:name=".simple.BasicHeuristicsService"
+            android:label="Basic Heuristics Autofill Service"
+            android:permission="android.permission.BIND_AUTOFILL_SERVICE">
+
+            <intent-filter>
+                <action android:name="android.service.autofill.AutofillService" />
+            </intent-filter>
+        </service>
+
+        <activity
+            android:name=".AuthActivity"
+            android:taskAffinity=".AuthActivity"
+            android:label="@string/authentication_name" />
+
+        <activity
+            android:name=".ManualActivity"
+            android:taskAffinity=".ManualActivity"
+            android:label="@string/manual_name" />
+
+        <activity
+            android:name=".ManualFieldPickerActivity"
+            android:taskAffinity=".ManualActivity"
+            android:label="@string/manual_field_picker_name" />
+
+        <!-- Including launcher icon for Autofill Settings to convenience. Not necessary for a
+        real service. -->
+        <activity
+            android:name=".settings.SettingsActivity"
+            android:exported="true"
+            android:label="@string/settings_name"
+            android:taskAffinity=".settings.SettingsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java
new file mode 100644
index 0000000..e1660b7
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java
@@ -0,0 +1,227 @@
+/*
+ * 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 com.example.android.autofill.service;
+
+import android.app.PendingIntent;
+import android.app.assist.AssistStructure;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.text.Editable;
+import android.widget.EditText;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+
+import com.example.android.autofill.service.data.ClientViewMetadata;
+import com.example.android.autofill.service.data.ClientViewMetadataBuilder;
+import com.example.android.autofill.service.data.DataCallback;
+import com.example.android.autofill.service.data.adapter.DatasetAdapter;
+import com.example.android.autofill.service.data.adapter.ResponseAdapter;
+import com.example.android.autofill.service.data.source.DefaultFieldTypesSource;
+import com.example.android.autofill.service.data.source.local.DefaultFieldTypesLocalJsonSource;
+import com.example.android.autofill.service.data.source.local.DigitalAssetLinksRepository;
+import com.example.android.autofill.service.data.source.local.LocalAutofillDataSource;
+import com.example.android.autofill.service.data.source.local.dao.AutofillDao;
+import com.example.android.autofill.service.data.source.local.db.AutofillDatabase;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.settings.MyPreferences;
+import com.example.android.autofill.service.util.AppExecutors;
+import com.google.gson.GsonBuilder;
+
+import java.util.HashMap;
+import java.util.List;
+
+import static android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE;
+import static android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT;
+import static com.example.android.autofill.service.util.Util.EXTRA_DATASET_NAME;
+import static com.example.android.autofill.service.util.Util.EXTRA_FOR_RESPONSE;
+import static com.example.android.autofill.service.util.Util.logw;
+
+
+/**
+ * This Activity controls the UI for logging in to the Autofill service.
+ * It is launched when an Autofill Response or specific Dataset within the Response requires
+ * authentication to access. It bundles the result in an Intent.
+ */
+public class AuthActivity extends AppCompatActivity {
+
+    // Unique id for dataset intents.
+    private static int sDatasetPendingIntentId = 0;
+
+    private LocalAutofillDataSource mLocalAutofillDataSource;
+    private DigitalAssetLinksRepository mDalRepository;
+    private EditText mMasterPassword;
+    private DatasetAdapter mDatasetAdapter;
+    private ResponseAdapter mResponseAdapter;
+    private ClientViewMetadata mClientViewMetadata;
+    private String mPackageName;
+    private Intent mReplyIntent;
+    private MyPreferences mPreferences;
+
+    public static IntentSender getAuthIntentSenderForResponse(Context context) {
+        final Intent intent = new Intent(context, AuthActivity.class);
+        return PendingIntent.getActivity(context, 0, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
+    }
+
+    public static IntentSender getAuthIntentSenderForDataset(Context originContext,
+            String datasetName) {
+        Intent intent = new Intent(originContext, AuthActivity.class);
+        intent.putExtra(EXTRA_DATASET_NAME, datasetName);
+        intent.putExtra(EXTRA_FOR_RESPONSE, false);
+        return PendingIntent.getActivity(originContext, ++sDatasetPendingIntentId, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.multidataset_service_auth_activity);
+        SharedPreferences sharedPreferences =
+                getSharedPreferences(LocalAutofillDataSource.SHARED_PREF_KEY, Context.MODE_PRIVATE);
+        DefaultFieldTypesSource defaultFieldTypesSource =
+                DefaultFieldTypesLocalJsonSource.getInstance(getResources(),
+                        new GsonBuilder().create());
+        AutofillDao autofillDao = AutofillDatabase.getInstance(this,
+                defaultFieldTypesSource, new AppExecutors()).autofillDao();
+        mLocalAutofillDataSource = LocalAutofillDataSource.getInstance(sharedPreferences,
+                autofillDao, new AppExecutors());
+        mDalRepository = DigitalAssetLinksRepository.getInstance(getPackageManager());
+        mMasterPassword = findViewById(R.id.master_password);
+        mPackageName = getPackageName();
+        mPreferences = MyPreferences.getInstance(this);
+        findViewById(R.id.login).setOnClickListener((view) -> login());
+        findViewById(R.id.cancel).setOnClickListener((view) -> {
+            onFailure();
+            AuthActivity.this.finish();
+        });
+    }
+
+    private void login() {
+        Editable password = mMasterPassword.getText();
+        String correctPassword = MyPreferences.getInstance(AuthActivity.this).getMasterPassword();
+        if (password.toString().equals(correctPassword)) {
+            onSuccess();
+        } else {
+            Toast.makeText(this, "Password incorrect", Toast.LENGTH_SHORT).show();
+            onFailure();
+        }
+    }
+
+    @Override
+    public void finish() {
+        if (mReplyIntent != null) {
+            setResult(RESULT_OK, mReplyIntent);
+        } else {
+            setResult(RESULT_CANCELED);
+        }
+        super.finish();
+    }
+
+    private void onFailure() {
+        logw("Failed auth.");
+        mReplyIntent = null;
+    }
+
+    private void onSuccess() {
+        Intent intent = getIntent();
+        boolean forResponse = intent.getBooleanExtra(EXTRA_FOR_RESPONSE, true);
+        AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE);
+        ClientParser clientParser = new ClientParser(structure);
+        mReplyIntent = new Intent();
+        mLocalAutofillDataSource.getFieldTypeByAutofillHints(
+                new DataCallback<HashMap<String, FieldTypeWithHeuristics>>() {
+            @Override
+            public void onLoaded(HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint) {
+                ClientViewMetadataBuilder builder = new ClientViewMetadataBuilder(clientParser,
+                        fieldTypesByAutofillHint);
+                mClientViewMetadata = builder.buildClientViewMetadata();
+                mDatasetAdapter = new DatasetAdapter(clientParser);
+                mResponseAdapter = new ResponseAdapter(AuthActivity.this,
+                        mClientViewMetadata, mPackageName, mDatasetAdapter);
+                if (forResponse) {
+                    fetchAllDatasetsAndSetIntent(fieldTypesByAutofillHint);
+                } else {
+                    String datasetName = intent.getStringExtra(EXTRA_DATASET_NAME);
+                    fetchDatasetAndSetIntent(fieldTypesByAutofillHint, datasetName);
+                }
+            }
+
+            @Override
+            public void onDataNotAvailable(String msg, Object... params) {
+
+            }
+        });
+    }
+
+    private void fetchDatasetAndSetIntent(
+            HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint, String datasetName) {
+        mLocalAutofillDataSource.getAutofillDataset(mClientViewMetadata.getAllHints(),
+                datasetName, new DataCallback<DatasetWithFilledAutofillFields>() {
+                    @Override
+                    public void onLoaded(DatasetWithFilledAutofillFields dataset) {
+                        String datasetName = dataset.autofillDataset.getDatasetName();
+                        RemoteViews remoteViews = RemoteViewsHelper.viewsWithNoAuth(
+                                mPackageName, datasetName);
+                        setDatasetIntent(mDatasetAdapter.buildDataset(fieldTypesByAutofillHint,
+                                dataset, remoteViews));
+                        finish();
+                    }
+
+                    @Override
+                    public void onDataNotAvailable(String msg, Object... params) {
+                        logw(msg, params);
+                        finish();
+                    }
+                });
+    }
+
+    private void fetchAllDatasetsAndSetIntent(
+            HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint) {
+        mLocalAutofillDataSource.getAutofillDatasets(mClientViewMetadata.getAllHints(),
+                new DataCallback<List<DatasetWithFilledAutofillFields>>() {
+                    @Override
+                    public void onLoaded(List<DatasetWithFilledAutofillFields> datasets) {
+                        boolean datasetAuth = mPreferences.isDatasetAuth();
+                        FillResponse fillResponse = mResponseAdapter.buildResponse(
+                                fieldTypesByAutofillHint, datasets, datasetAuth);
+                        setResponseIntent(fillResponse);
+                        finish();
+                    }
+
+                    @Override
+                    public void onDataNotAvailable(String msg, Object... params) {
+                        logw(msg, params);
+                        finish();
+                    }
+                });
+    }
+
+    private void setResponseIntent(FillResponse fillResponse) {
+        mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse);
+    }
+
+    private void setDatasetIntent(Dataset dataset) {
+        mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, dataset);
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHintProperties.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHintProperties.java
new file mode 100644
index 0000000..8314eb3
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHintProperties.java
@@ -0,0 +1,92 @@
+/*
+ * 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 com.example.android.autofill.service;
+
+import android.view.View;
+
+import com.example.android.autofill.service.model.FilledAutofillField;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Holds the properties associated with an autofill hint in this Autofill Service.
+ */
+public final class AutofillHintProperties {
+
+    private String mAutofillHint;
+    private FakeFieldGenerator mFakeFieldGenerator;
+    private Set<Integer> mValidTypes;
+    private int mSaveType;
+    private int mPartition;
+
+    public AutofillHintProperties(String autofillHint, int saveType, int partitionNumber,
+            FakeFieldGenerator fakeFieldGenerator, Integer... validTypes) {
+        mAutofillHint = autofillHint;
+        mSaveType = saveType;
+        mPartition = partitionNumber;
+        mFakeFieldGenerator = fakeFieldGenerator;
+        mValidTypes = new HashSet<>(Arrays.asList(validTypes));
+    }
+
+    /**
+     * Generates dummy autofill field data that is relevant to the autofill hint.
+     */
+    public FilledAutofillField generateFakeField(int seed, String datasetId) {
+        return mFakeFieldGenerator.generate(seed, datasetId);
+    }
+
+    /**
+     * Returns autofill hint associated with these properties. If you save a field that uses a W3C
+     * hint, there is a chance this will return a different but analogous hint, when applicable.
+     * For example, W3C has hint 'email' and {@link android.view.View} has hint 'emailAddress', so
+     * the W3C hint should map to the hint defined in {@link android.view.View} ('emailAddress').
+     */
+    public String getAutofillHint() {
+        return mAutofillHint;
+    }
+
+    /**
+     * Returns how this hint maps to a {@link android.service.autofill.SaveInfo} type.
+     */
+    public int getSaveType() {
+        return mSaveType;
+    }
+
+    /**
+     * Returns which data partition this autofill hint should be a part of. See partitions defined
+     * in {@link AutofillHints}.
+     */
+    public int getPartition() {
+        return mPartition;
+    }
+
+
+    /**
+     * Sometimes, data for a hint should only be stored as a certain AutofillValue type. For
+     * example, it is recommended that data representing a Credit Card Expiration date, annotated
+     * with the hint {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, should
+     * only be stored as {@link View#AUTOFILL_TYPE_DATE}.
+     */
+    public boolean isValidType(int type) {
+        return mValidTypes.contains(type);
+    }
+
+    public Set<Integer> getTypes() {
+        return mValidTypes;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHints.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHints.java
new file mode 100644
index 0000000..d43071f
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHints.java
@@ -0,0 +1,175 @@
+/*
+ * 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 com.example.android.autofill.service;
+
+import android.support.annotation.NonNull;
+
+import com.example.android.autofill.service.model.FakeData;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.model.FilledAutofillField;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+import static com.example.android.autofill.service.util.Util.logd;
+import static com.example.android.autofill.service.util.Util.logw;
+import static java.util.stream.Collectors.toList;
+
+public final class AutofillHints {
+    public static final int PARTITION_ALL = -1;
+    public static final int PARTITION_OTHER = 0;
+    public static final int PARTITION_ADDRESS = 1;
+    public static final int PARTITION_EMAIL = 2;
+    public static final int PARTITION_CREDIT_CARD = 3;
+    public static final int[] PARTITIONS = {
+            PARTITION_OTHER, PARTITION_ADDRESS, PARTITION_EMAIL, PARTITION_CREDIT_CARD
+    };
+
+    private AutofillHints() {
+    }
+
+    public static FilledAutofillField generateFakeField(
+            FieldTypeWithHeuristics fieldTypeWithHeuristics, String packageName, int seed,
+            String datasetId) {
+        FakeData fakeData = fieldTypeWithHeuristics.fieldType.getFakeData();
+        String fieldTypeName = fieldTypeWithHeuristics.fieldType.getTypeName();
+        String text = null;
+        Long date = null;
+        Boolean toggle = null;
+        if (fakeData.strictExampleSet != null && fakeData.strictExampleSet.strings != null &&
+                fakeData.strictExampleSet.strings.size() > 0 &&
+                !fakeData.strictExampleSet.strings.get(0).isEmpty()) {
+            List<String> choices = fakeData.strictExampleSet.strings;
+            text = choices.get(seed % choices.size());
+        } else if (fakeData.textTemplate != null) {
+            text = fakeData.textTemplate.replace("seed", "" + seed)
+                    .replace("curr_time", "" + Calendar.getInstance().getTimeInMillis());
+        } else if (fakeData.dateTemplate != null) {
+            if (fakeData.dateTemplate.contains("curr_time")) {
+                date = Calendar.getInstance().getTimeInMillis();
+            }
+        }
+        return new FilledAutofillField(datasetId, fieldTypeName, text, date, toggle);
+    }
+
+    public static String getFieldTypeNameFromAutofillHints(
+            HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint,
+            @NonNull List<String> hints) {
+        return getFieldTypeNameFromAutofillHints(fieldTypesByAutofillHint, hints, PARTITION_ALL);
+    }
+
+    public static String getFieldTypeNameFromAutofillHints(
+            HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint,
+            @NonNull List<String> hints, int partition) {
+        List<String> fieldTypeNames = removePrefixes(hints)
+                .stream()
+                .filter(fieldTypesByAutofillHint::containsKey)
+                .map(fieldTypesByAutofillHint::get)
+                .filter(Objects::nonNull)
+                .filter((fieldTypeWithHints) ->
+                        matchesPartition(fieldTypeWithHints.fieldType.getPartition(), partition))
+                .map(FieldTypeWithHeuristics::getFieldType).map(FieldType::getTypeName)
+                .collect(toList());
+        if (fieldTypeNames != null && fieldTypeNames.size() > 0) {
+            return fieldTypeNames.get(0);
+        } else {
+            return null;
+        }
+    }
+
+    public static boolean matchesPartition(int partition, int otherPartition) {
+        return partition == PARTITION_ALL || otherPartition == PARTITION_ALL ||
+                partition == otherPartition;
+    }
+
+    private static List<String> removePrefixes(@NonNull List<String> hints) {
+        List<String> hintsWithoutPrefixes = new ArrayList<>();
+        String nextHint = null;
+        for (int i = 0; i < hints.size(); i++) {
+            String hint = hints.get(i);
+            if (i < hints.size() - 1) {
+                nextHint = hints.get(i + 1);
+            }
+            // First convert the compound W3C autofill hints
+            if (isW3cSectionPrefix(hint) && i < hints.size() - 1) {
+                i++;
+                hint = hints.get(i);
+                logd("Hint is a W3C section prefix; using %s instead", hint);
+                if (i < hints.size() - 1) {
+                    nextHint = hints.get(i + 1);
+                }
+            }
+            if (isW3cTypePrefix(hint) && nextHint != null && isW3cTypeHint(nextHint)) {
+                hint = nextHint;
+                i++;
+                logd("Hint is a W3C type prefix; using %s instead", hint);
+            }
+            if (isW3cAddressType(hint) && nextHint != null) {
+                hint = nextHint;
+                i++;
+                logd("Hint is a W3C address prefix; using %s instead", hint);
+            }
+            hintsWithoutPrefixes.add(hint);
+        }
+        return hintsWithoutPrefixes;
+    }
+
+    private static boolean isW3cSectionPrefix(@NonNull String hint) {
+        return hint.startsWith(W3cHints.PREFIX_SECTION);
+    }
+
+    private static boolean isW3cAddressType(@NonNull String hint) {
+        switch (hint) {
+            case W3cHints.SHIPPING:
+            case W3cHints.BILLING:
+                return true;
+        }
+        return false;
+    }
+
+    private static boolean isW3cTypePrefix(@NonNull String hint) {
+        switch (hint) {
+            case W3cHints.PREFIX_WORK:
+            case W3cHints.PREFIX_FAX:
+            case W3cHints.PREFIX_HOME:
+            case W3cHints.PREFIX_PAGER:
+                return true;
+        }
+        return false;
+    }
+
+    private static boolean isW3cTypeHint(@NonNull String hint) {
+        switch (hint) {
+            case W3cHints.TEL:
+            case W3cHints.TEL_COUNTRY_CODE:
+            case W3cHints.TEL_NATIONAL:
+            case W3cHints.TEL_AREA_CODE:
+            case W3cHints.TEL_LOCAL:
+            case W3cHints.TEL_LOCAL_PREFIX:
+            case W3cHints.TEL_LOCAL_SUFFIX:
+            case W3cHints.TEL_EXTENSION:
+            case W3cHints.EMAIL:
+            case W3cHints.IMPP:
+                return true;
+        }
+        logw("Invalid W3C type hint: %s", hint);
+        return false;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/ClientParser.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/ClientParser.java
new file mode 100644
index 0000000..048c001
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/ClientParser.java
@@ -0,0 +1,72 @@
+/*
+ * 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 com.example.android.autofill.service;
+
+import android.app.assist.AssistStructure;
+import android.support.annotation.NonNull;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+import static android.app.assist.AssistStructure.ViewNode;
+
+/**
+ * Wrapper for {@link AssistStructure} to make it easy to parse.
+ */
+public final class ClientParser {
+    private final List<AssistStructure> mStructures;
+
+    public ClientParser(@NonNull List<AssistStructure> structures) {
+        Preconditions.checkNotNull(structures);
+        mStructures = structures;
+    }
+
+    public ClientParser(@NonNull AssistStructure structure) {
+        this(ImmutableList.of(structure));
+    }
+
+    /**
+     * Traverses through the {@link AssistStructure} and does something at each {@link ViewNode}.
+     *
+     * @param processor contains action to be performed on each {@link ViewNode}.
+     */
+    public void parse(NodeProcessor processor) {
+        for (AssistStructure structure : mStructures) {
+            int nodes = structure.getWindowNodeCount();
+            for (int i = 0; i < nodes; i++) {
+                AssistStructure.ViewNode viewNode = structure.getWindowNodeAt(i).getRootViewNode();
+                traverseRoot(viewNode, processor);
+            }
+        }
+    }
+
+    private void traverseRoot(AssistStructure.ViewNode viewNode, NodeProcessor processor) {
+        processor.processNode(viewNode);
+        int childrenSize = viewNode.getChildCount();
+        if (childrenSize > 0) {
+            for (int i = 0; i < childrenSize; i++) {
+                traverseRoot(viewNode.getChildAt(i), processor);
+            }
+        }
+    }
+
+    public interface NodeProcessor {
+        void processNode(ViewNode node);
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/FakeFieldGenerator.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/FakeFieldGenerator.java
new file mode 100644
index 0000000..8d0754a
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/FakeFieldGenerator.java
@@ -0,0 +1,22 @@
+/*
+ * 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 com.example.android.autofill.service;
+
+import com.example.android.autofill.service.model.FilledAutofillField;
+
+interface FakeFieldGenerator {
+    FilledAutofillField generate(int seed, String datasetId);
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/ManualActivity.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/ManualActivity.java
new file mode 100644
index 0000000..a9acaa5
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/ManualActivity.java
@@ -0,0 +1,345 @@
+/*
+ * 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.example.android.autofill.service;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.assist.AssistStructure;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.DividerItemDecoration;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.example.android.autofill.service.data.ClientViewMetadata;
+import com.example.android.autofill.service.data.ClientViewMetadataBuilder;
+import com.example.android.autofill.service.data.DataCallback;
+import com.example.android.autofill.service.data.adapter.DatasetAdapter;
+import com.example.android.autofill.service.data.adapter.ResponseAdapter;
+import com.example.android.autofill.service.data.source.DefaultFieldTypesSource;
+import com.example.android.autofill.service.data.source.local.DefaultFieldTypesLocalJsonSource;
+import com.example.android.autofill.service.data.source.local.LocalAutofillDataSource;
+import com.example.android.autofill.service.data.source.local.dao.AutofillDao;
+import com.example.android.autofill.service.data.source.local.db.AutofillDatabase;
+import com.example.android.autofill.service.model.AutofillDataset;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.model.FilledAutofillField;
+import com.example.android.autofill.service.settings.MyPreferences;
+import com.example.android.autofill.service.util.AppExecutors;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.GsonBuilder;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE;
+import static android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT;
+import static com.example.android.autofill.service.util.Util.logd;
+
+/**
+ * When the user long-presses on an autofillable field and selects "Autofill", this activity is
+ * launched to allow the user to select the dataset.
+ */
+public class ManualActivity extends AppCompatActivity {
+
+    private static final int RC_SELECT_FIELD = 1;
+
+    // Unique id for dataset intents.
+    private static int sDatasetPendingIntentId = 0;
+
+    private LocalAutofillDataSource mLocalAutofillDataSource;
+    private DatasetAdapter mDatasetAdapter;
+    private ResponseAdapter mResponseAdapter;
+    private ClientViewMetadata mClientViewMetadata;
+    private String mPackageName;
+    private Intent mReplyIntent;
+    private MyPreferences mPreferences;
+    private List<DatasetWithFilledAutofillFields> mAllDatasets;
+    private RecyclerView mRecyclerView;
+
+    public static IntentSender getManualIntentSenderForResponse(Context context) {
+        final Intent intent = new Intent(context, ManualActivity.class);
+        return PendingIntent.getActivity(context, 0, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.multidataset_service_manual_activity);
+        SharedPreferences sharedPreferences =
+                getSharedPreferences(LocalAutofillDataSource.SHARED_PREF_KEY, Context.MODE_PRIVATE);
+        DefaultFieldTypesSource defaultFieldTypesSource =
+                DefaultFieldTypesLocalJsonSource.getInstance(getResources(),
+                        new GsonBuilder().create());
+        AutofillDao autofillDao = AutofillDatabase.getInstance(this,
+                defaultFieldTypesSource, new AppExecutors()).autofillDao();
+        mLocalAutofillDataSource = LocalAutofillDataSource.getInstance(sharedPreferences,
+                autofillDao, new AppExecutors());
+        mPackageName = getPackageName();
+        mPreferences = MyPreferences.getInstance(this);
+        mRecyclerView = findViewById(R.id.suggestionsList);
+        mRecyclerView.addItemDecoration(new DividerItemDecoration(this, VERTICAL));
+        mLocalAutofillDataSource.getAllAutofillDatasets(
+                new DataCallback<List<DatasetWithFilledAutofillFields>>() {
+                    @Override
+                    public void onLoaded(List<DatasetWithFilledAutofillFields> datasets) {
+                        mAllDatasets = datasets;
+                        buildAdapter();
+                    }
+
+                    @Override
+                    public void onDataNotAvailable(String msg, Object... params) {
+
+                    }
+                });
+    }
+
+    private void buildAdapter() {
+        List<String> datasetIds = new ArrayList<>();
+        List<String> datasetNames = new ArrayList<>();
+        List<List<String>> allFieldTypes = new ArrayList<>();
+        for (DatasetWithFilledAutofillFields dataset : mAllDatasets) {
+            String datasetName = dataset.autofillDataset.getDatasetName();
+            String datasetId = dataset.autofillDataset.getId();
+            List<String> fieldTypes = new ArrayList<>();
+            for (FilledAutofillField filledAutofillField : dataset.filledAutofillFields) {
+                fieldTypes.add(filledAutofillField.getFieldTypeName());
+            }
+            datasetIds.add(datasetId);
+            datasetNames.add(datasetName);
+            allFieldTypes.add(fieldTypes);
+        }
+        AutofillDatasetsAdapter adapter = new AutofillDatasetsAdapter(datasetIds, datasetNames,
+                allFieldTypes, this);
+        mRecyclerView.setAdapter(adapter);
+    }
+
+    @Override
+    public void finish() {
+        if (mReplyIntent != null) {
+            setResult(RESULT_OK, mReplyIntent);
+        } else {
+            setResult(RESULT_CANCELED);
+        }
+        super.finish();
+    }
+
+    private void onFieldSelected(FilledAutofillField field, FieldType fieldType) {
+        DatasetWithFilledAutofillFields datasetWithFilledAutofillFields = new DatasetWithFilledAutofillFields();
+        String newDatasetId = UUID.randomUUID().toString();
+        FilledAutofillField copyOfField = new FilledAutofillField(newDatasetId,
+                field.getFieldTypeName(), field.getTextValue(), field.getDateValue(),
+                field.getToggleValue());
+        String datasetName = "dataset-manual";
+        AutofillDataset autofillDataset = new AutofillDataset(newDatasetId, datasetName, mPackageName);
+        datasetWithFilledAutofillFields.filledAutofillFields = ImmutableList.of(copyOfField);
+        datasetWithFilledAutofillFields.autofillDataset = autofillDataset;
+        Intent intent = getIntent();
+        AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE);
+        ClientParser clientParser = new ClientParser(structure);
+        mReplyIntent = new Intent();
+        mLocalAutofillDataSource.getFieldTypeByAutofillHints(
+                new DataCallback<HashMap<String, FieldTypeWithHeuristics>>() {
+                    @Override
+                    public void onLoaded(HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint) {
+                        ClientViewMetadataBuilder builder = new ClientViewMetadataBuilder(clientParser,
+                                fieldTypesByAutofillHint);
+                        mClientViewMetadata = builder.buildClientViewMetadata();
+                        mDatasetAdapter = new DatasetAdapter(clientParser);
+                        mResponseAdapter = new ResponseAdapter(ManualActivity.this,
+                                mClientViewMetadata, mPackageName, mDatasetAdapter);
+                        FillResponse fillResponse = mResponseAdapter.buildResponseForFocusedNode(
+                                datasetName, field, fieldType);
+                        setResponseIntent(fillResponse);
+                        finish();
+                    }
+
+                    @Override
+                    public void onDataNotAvailable(String msg, Object... params) {
+                    }
+                });
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (requestCode != RC_SELECT_FIELD || resultCode != RESULT_OK) {
+            logd("Ignoring requestCode == %d | resultCode == %d", requestCode,
+                    resultCode);
+            return;
+        }
+        String datasetId = data.getStringExtra(ManualFieldPickerActivity.EXTRA_SELECTED_FIELD_DATASET_ID);
+        String fieldTypeName = data.getStringExtra(ManualFieldPickerActivity.EXTRA_SELECTED_FIELD_TYPE_NAME);
+        mLocalAutofillDataSource.getFilledAutofillField(datasetId, fieldTypeName, new DataCallback<FilledAutofillField>() {
+            @Override
+            public void onLoaded(FilledAutofillField field) {
+                mLocalAutofillDataSource.getFieldType(field.getFieldTypeName(), new DataCallback<FieldType>() {
+                    @Override
+                    public void onLoaded(FieldType fieldType) {
+                        onFieldSelected(field, fieldType);
+                    }
+
+                    @Override
+                    public void onDataNotAvailable(String msg, Object... params) {
+
+                    }
+                });
+            }
+
+            @Override
+            public void onDataNotAvailable(String msg, Object... params) {
+
+            }
+        });
+    }
+
+
+    private void updateHeuristics() {
+//        TODO: update heuristics in data source; something like:
+//        mLocalAutofillDataSource.getAutofillDataset(mClientViewMetadata.getAllHints(),
+//                datasetName, new DataCallback<DatasetWithFilledAutofillFields>() {
+//                    @Override
+//                    public void onLoaded(DatasetWithFilledAutofillFields dataset) {
+//                        String datasetName = dataset.autofillDataset.getDatasetName();
+//                        RemoteViews remoteViews = RemoteViewsHelper.viewsWithNoAuth(
+//                                mPackageName, datasetName);
+//                        setDatasetIntent(mDatasetAdapter.buildDataset(fieldTypesByAutofillHint,
+//                                dataset, remoteViews));
+//                        finish();
+//                    }
+//
+//                    @Override
+//                    public void onDataNotAvailable(String msg, Object... params) {
+//                        logw(msg, params);
+//                        finish();
+//                    }
+//                });
+    }
+
+    private void setResponseIntent(FillResponse fillResponse) {
+        mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse);
+    }
+
+    private void setDatasetIntent(Dataset dataset) {
+        mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, dataset);
+    }
+
+    /**
+     * Adapter for the {@link RecyclerView} that holds a list of datasets.
+     */
+    private static class AutofillDatasetsAdapter extends RecyclerView.Adapter<DatasetViewHolder> {
+
+        private final List<String> mDatasetIds;
+        private final List<String> mDatasetNames;
+        private final List<List<String>> mFieldTypes;
+        private final Activity mActivity;
+
+        AutofillDatasetsAdapter(List<String> datasetIds, List<String> datasetNames,
+                List<List<String>> fieldTypes, Activity activity) {
+            mDatasetIds = datasetIds;
+            mDatasetNames = datasetNames;
+            mFieldTypes = fieldTypes;
+            mActivity = activity;
+        }
+
+        @Override
+        public DatasetViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            return DatasetViewHolder.newInstance(parent, mActivity);
+        }
+
+        @Override
+        public void onBindViewHolder(final DatasetViewHolder holder, final int position) {
+            holder.bind(mDatasetIds.get(position), mDatasetNames.get(position),
+                    mFieldTypes.get(position));
+        }
+
+        @Override
+        public int getItemCount() {
+            return mDatasetNames.size();
+        }
+    }
+
+    /**
+     * Contains views needed in each row of the list of datasets.
+     */
+    private static class DatasetViewHolder extends RecyclerView.ViewHolder {
+        private final View mRootView;
+        private final TextView mDatasetNameText;
+        private final TextView mFieldTypesText;
+        private final Activity mActivity;
+
+        public DatasetViewHolder(View itemView, Activity activity) {
+            super(itemView);
+            mRootView = itemView;
+            mDatasetNameText = itemView.findViewById(R.id.datasetName);
+            mFieldTypesText = itemView.findViewById(R.id.fieldTypes);
+            mActivity = activity;
+        }
+
+        public static DatasetViewHolder newInstance(ViewGroup parent, Activity activity) {
+            return new DatasetViewHolder(LayoutInflater.from(parent.getContext())
+                    .inflate(R.layout.dataset_suggestion, parent, false), activity);
+        }
+
+        public void bind(String datasetId, String datasetName, List<String> fieldTypes) {
+            mDatasetNameText.setText(datasetName);
+            String firstFieldType = null;
+            String secondFieldType = null;
+            int numOfFieldTypes = 0;
+            if (fieldTypes != null) {
+                numOfFieldTypes = fieldTypes.size();
+                if (numOfFieldTypes > 0) {
+                    firstFieldType = fieldTypes.get(0);
+                }
+                if (numOfFieldTypes > 1) {
+                    secondFieldType = fieldTypes.get(1);
+                }
+            }
+            String fieldTypesString;
+            if (numOfFieldTypes == 1) {
+                fieldTypesString = "Contains data for " + firstFieldType + ".";
+            } else if (numOfFieldTypes == 2) {
+                fieldTypesString = "Contains data for " + firstFieldType + " and " + secondFieldType + ".";
+            } else if (numOfFieldTypes > 2) {
+                fieldTypesString = "Contains data for " + firstFieldType + ", " + secondFieldType + ", and more.";
+            } else {
+                fieldTypesString = "Ignore: Contains no data.";
+            }
+            mFieldTypesText.setText(fieldTypesString);
+            mRootView.setOnClickListener((view) -> {
+                Intent intent = ManualFieldPickerActivity.getIntent(mActivity, datasetId);
+                mActivity.startActivityForResult(intent, RC_SELECT_FIELD);
+            });
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/ManualFieldPickerActivity.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/ManualFieldPickerActivity.java
new file mode 100644
index 0000000..608ac95
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/ManualFieldPickerActivity.java
@@ -0,0 +1,160 @@
+/*
+ * 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 com.example.android.autofill.service;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.DividerItemDecoration;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.example.android.autofill.service.data.DataCallback;
+import com.example.android.autofill.service.data.source.DefaultFieldTypesSource;
+import com.example.android.autofill.service.data.source.local.DefaultFieldTypesLocalJsonSource;
+import com.example.android.autofill.service.data.source.local.LocalAutofillDataSource;
+import com.example.android.autofill.service.data.source.local.dao.AutofillDao;
+import com.example.android.autofill.service.data.source.local.db.AutofillDatabase;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FilledAutofillField;
+import com.example.android.autofill.service.util.AppExecutors;
+import com.google.gson.GsonBuilder;
+
+import java.util.List;
+
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+
+public class ManualFieldPickerActivity extends AppCompatActivity {
+    private static final String EXTRA_DATASET_ID = "extra_dataset_id";
+    public static final String EXTRA_SELECTED_FIELD_DATASET_ID = "selected_field_dataset_id";
+    public static final String EXTRA_SELECTED_FIELD_TYPE_NAME = "selected_field_type_name";
+
+    private LocalAutofillDataSource mLocalAutofillDataSource;
+
+    private RecyclerView mRecyclerView;
+    private TextView mListTitle;
+    private DatasetWithFilledAutofillFields mDataset;
+
+    public static Intent getIntent(Context originContext, String datasetId) {
+        Intent intent = new Intent(originContext, ManualFieldPickerActivity.class);
+        intent.putExtra(EXTRA_DATASET_ID, datasetId);
+        return intent;
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_field_picker);
+        SharedPreferences sharedPreferences = getSharedPreferences(
+                LocalAutofillDataSource.SHARED_PREF_KEY, Context.MODE_PRIVATE);
+        DefaultFieldTypesSource defaultFieldTypesSource =
+                DefaultFieldTypesLocalJsonSource.getInstance(getResources(),
+                        new GsonBuilder().create());
+        AutofillDao autofillDao = AutofillDatabase.getInstance(this,
+                defaultFieldTypesSource, new AppExecutors()).autofillDao();
+        String datasetId = getIntent().getStringExtra(EXTRA_DATASET_ID);
+        mRecyclerView = findViewById(R.id.fieldsList);
+        mRecyclerView.addItemDecoration(new DividerItemDecoration(this, VERTICAL));
+        mListTitle = findViewById(R.id.listTitle);
+        mLocalAutofillDataSource = LocalAutofillDataSource.getInstance(sharedPreferences,
+                autofillDao, new AppExecutors());
+        mLocalAutofillDataSource.getAutofillDatasetWithId(datasetId,
+                new DataCallback<DatasetWithFilledAutofillFields>() {
+                    @Override
+                    public void onLoaded(DatasetWithFilledAutofillFields dataset) {
+                        mDataset = dataset;
+                        if (mDataset != null) {
+                            onLoadedDataset();
+                        }
+                    }
+
+                    @Override
+                    public void onDataNotAvailable(String msg, Object... params) {
+
+                    }
+                });
+    }
+
+    public void onSelectedDataset(FilledAutofillField field) {
+        Intent data = new Intent()
+                .putExtra(EXTRA_SELECTED_FIELD_DATASET_ID, field.getDatasetId())
+                .putExtra(EXTRA_SELECTED_FIELD_TYPE_NAME, field.getFieldTypeName());
+        setResult(RESULT_OK, data);
+        finish();
+    }
+
+    public void onLoadedDataset() {
+        FieldsAdapter fieldsAdapter = new FieldsAdapter(this, mDataset.filledAutofillFields);
+        mRecyclerView.setAdapter(fieldsAdapter);
+        mListTitle.setText(getString(R.string.manual_data_picker_title,
+                mDataset.autofillDataset.getDatasetName()));
+    }
+
+    private static class FieldsAdapter extends RecyclerView.Adapter<FieldViewHolder> {
+        private final Activity mActivity;
+        private final List<FilledAutofillField> mFields;
+
+        public FieldsAdapter(Activity activity, List<FilledAutofillField> fields) {
+            mActivity = activity;
+            mFields = fields;
+        }
+
+        @Override
+        public FieldViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            return new FieldViewHolder(LayoutInflater.from(parent.getContext())
+                    .inflate(R.layout.dataset_field, parent, false), mActivity);
+        }
+
+        @Override
+        public void onBindViewHolder(FieldViewHolder holder, int position) {
+            FilledAutofillField field = mFields.get(position);
+            holder.bind(field);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mFields.size();
+        }
+    }
+
+    private static class FieldViewHolder extends RecyclerView.ViewHolder {
+        private final View mRootView;
+        private final TextView mFieldTypeText;
+        private final Activity mActivity;
+
+        public FieldViewHolder(View itemView, Activity activity) {
+            super(itemView);
+            mRootView = itemView;
+            mFieldTypeText = itemView.findViewById(R.id.fieldType);
+            mActivity = activity;
+        }
+
+        public void bind(FilledAutofillField field) {
+            mFieldTypeText.setText(field.getFieldTypeName());
+            mRootView.setOnClickListener((view) -> {
+                ((ManualFieldPickerActivity) mActivity).onSelectedDataset(field);
+            });
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java
new file mode 100644
index 0000000..e9cdd6c
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java
@@ -0,0 +1,282 @@
+/*
+ * 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 com.example.android.autofill.service;
+
+import android.app.assist.AssistStructure;
+import android.content.Context;
+import android.content.IntentSender;
+import android.content.SharedPreferences;
+import android.os.CancellationSignal;
+import android.service.autofill.AutofillService;
+import android.service.autofill.FillCallback;
+import android.service.autofill.FillContext;
+import android.service.autofill.FillRequest;
+import android.service.autofill.FillResponse;
+import android.service.autofill.SaveCallback;
+import android.service.autofill.SaveRequest;
+import android.support.annotation.NonNull;
+import android.view.autofill.AutofillManager;
+import android.widget.RemoteViews;
+
+import com.example.android.autofill.service.data.AutofillDataBuilder;
+import com.example.android.autofill.service.data.ClientAutofillDataBuilder;
+import com.example.android.autofill.service.data.ClientViewMetadata;
+import com.example.android.autofill.service.data.ClientViewMetadataBuilder;
+import com.example.android.autofill.service.data.DataCallback;
+import com.example.android.autofill.service.data.adapter.DatasetAdapter;
+import com.example.android.autofill.service.data.adapter.ResponseAdapter;
+import com.example.android.autofill.service.data.source.DefaultFieldTypesSource;
+import com.example.android.autofill.service.data.source.PackageVerificationDataSource;
+import com.example.android.autofill.service.data.source.local.DefaultFieldTypesLocalJsonSource;
+import com.example.android.autofill.service.data.source.local.DigitalAssetLinksRepository;
+import com.example.android.autofill.service.data.source.local.LocalAutofillDataSource;
+import com.example.android.autofill.service.data.source.local.SharedPrefsPackageVerificationRepository;
+import com.example.android.autofill.service.data.source.local.dao.AutofillDao;
+import com.example.android.autofill.service.data.source.local.db.AutofillDatabase;
+import com.example.android.autofill.service.model.DalCheck;
+import com.example.android.autofill.service.model.DalInfo;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.settings.MyPreferences;
+import com.example.android.autofill.service.util.AppExecutors;
+import com.example.android.autofill.service.util.Util;
+import com.google.gson.GsonBuilder;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static com.example.android.autofill.service.util.Util.DalCheckRequirement;
+import static com.example.android.autofill.service.util.Util.bundleToString;
+import static com.example.android.autofill.service.util.Util.dumpStructure;
+import static com.example.android.autofill.service.util.Util.logVerboseEnabled;
+import static com.example.android.autofill.service.util.Util.logd;
+import static com.example.android.autofill.service.util.Util.loge;
+import static com.example.android.autofill.service.util.Util.logv;
+import static com.example.android.autofill.service.util.Util.logw;
+import static java.util.stream.Collectors.toList;
+
+public class MyAutofillService extends AutofillService {
+
+    private LocalAutofillDataSource mLocalAutofillDataSource;
+    private DigitalAssetLinksRepository mDalRepository;
+    private PackageVerificationDataSource mPackageVerificationRepository;
+    private AutofillDataBuilder mAutofillDataBuilder;
+    private ResponseAdapter mResponseAdapter;
+    private ClientViewMetadata mClientViewMetadata;
+    private MyPreferences mPreferences;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mPreferences = MyPreferences.getInstance(this);
+        Util.setLoggingLevel(mPreferences.getLoggingLevel());
+        SharedPreferences localAfDataSourceSharedPrefs =
+                getSharedPreferences(LocalAutofillDataSource.SHARED_PREF_KEY, Context.MODE_PRIVATE);
+        DefaultFieldTypesSource defaultFieldTypesSource =
+                DefaultFieldTypesLocalJsonSource.getInstance(getResources(),
+                        new GsonBuilder().create());
+        AutofillDao autofillDao = AutofillDatabase.getInstance(this,
+                defaultFieldTypesSource, new AppExecutors()).autofillDao();
+        mLocalAutofillDataSource = LocalAutofillDataSource.getInstance(localAfDataSourceSharedPrefs,
+                autofillDao, new AppExecutors());
+        mDalRepository = DigitalAssetLinksRepository.getInstance(getPackageManager());
+        mPackageVerificationRepository = SharedPrefsPackageVerificationRepository.getInstance(this);
+    }
+
+    @Override
+    public void onFillRequest(@NonNull FillRequest request,
+            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
+        List<FillContext> fillContexts = request.getFillContexts();
+        List<AssistStructure> structures =
+                fillContexts.stream().map(FillContext::getStructure).collect(toList());
+        AssistStructure latestStructure = fillContexts.get(fillContexts.size() - 1).getStructure();
+        ClientParser parser = new ClientParser(structures);
+
+        // Check user's settings for authenticating Responses and Datasets.
+        boolean responseAuth = mPreferences.isResponseAuth();
+        boolean datasetAuth = mPreferences.isDatasetAuth();
+        boolean manual = (request.getFlags() & FillRequest.FLAG_MANUAL_REQUEST) != 0;
+        mLocalAutofillDataSource.getFieldTypeByAutofillHints(
+                new DataCallback<HashMap<String, FieldTypeWithHeuristics>>() {
+                    @Override
+                    public void onLoaded(HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint) {
+                        DatasetAdapter datasetAdapter = new DatasetAdapter(parser);
+                        ClientViewMetadataBuilder clientViewMetadataBuilder =
+                                new ClientViewMetadataBuilder(parser, fieldTypesByAutofillHint);
+                        mClientViewMetadata = clientViewMetadataBuilder.buildClientViewMetadata();
+                        mResponseAdapter = new ResponseAdapter(MyAutofillService.this,
+                                mClientViewMetadata, getPackageName(), datasetAdapter);
+                        String packageName = latestStructure.getActivityComponent().getPackageName();
+                        if (!mPackageVerificationRepository.putPackageSignatures(packageName)) {
+                            callback.onFailure(getString(R.string.invalid_package_signature));
+                            return;
+                        }
+                        if (logVerboseEnabled()) {
+                            logv("onFillRequest(): clientState=%s",
+                                    bundleToString(request.getClientState()));
+                            dumpStructure(latestStructure);
+                        }
+                        cancellationSignal.setOnCancelListener(() ->
+                                logw("Cancel autofill not implemented in this sample.")
+                        );
+                        fetchDataAndGenerateResponse(fieldTypesByAutofillHint, responseAuth,
+                                datasetAuth, manual, callback);
+                    }
+
+                    @Override
+                    public void onDataNotAvailable(String msg, Object... params) {
+
+                    }
+                });
+    }
+
+    private void fetchDataAndGenerateResponse(
+            HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint, boolean responseAuth,
+            boolean datasetAuth, boolean manual, FillCallback callback) {
+        if (responseAuth) {
+            // If the entire Autofill Response is authenticated, AuthActivity is used
+            // to generate Response.
+            IntentSender sender = AuthActivity.getAuthIntentSenderForResponse(this);
+            RemoteViews remoteViews = RemoteViewsHelper.viewsWithAuth(getPackageName(),
+                    getString(R.string.autofill_sign_in_prompt));
+            FillResponse response = mResponseAdapter.buildResponse(sender, remoteViews);
+            if (response != null) {
+                callback.onSuccess(response);
+            }
+        } else {
+            mLocalAutofillDataSource.getAutofillDatasets(mClientViewMetadata.getAllHints(),
+                    new DataCallback<List<DatasetWithFilledAutofillFields>>() {
+                        @Override
+                        public void onLoaded(List<DatasetWithFilledAutofillFields> datasets) {
+                            if ((datasets == null || datasets.isEmpty()) && manual) {
+                                IntentSender sender = ManualActivity
+                                        .getManualIntentSenderForResponse(MyAutofillService.this);
+                                RemoteViews remoteViews = RemoteViewsHelper.viewsWithNoAuth(
+                                        getPackageName(),
+                                        getString(R.string.autofill_manual_prompt));
+                                FillResponse response = mResponseAdapter.buildManualResponse(sender,
+                                        remoteViews);
+                                if (response != null) {
+                                    callback.onSuccess(response);
+                                }
+                            } else {
+                                FillResponse response = mResponseAdapter.buildResponse(
+                                        fieldTypesByAutofillHint, datasets, datasetAuth);
+                                callback.onSuccess(response);
+                            }
+                        }
+
+                        @Override
+                        public void onDataNotAvailable(String msg, Object... params) {
+                            logw(msg, params);
+                            callback.onFailure(String.format(msg, params));
+                        }
+                    });
+        }
+    }
+
+    @Override
+    public void onSaveRequest(@NonNull SaveRequest request, @NonNull SaveCallback callback) {
+        List<FillContext> fillContexts = request.getFillContexts();
+        List<AssistStructure> structures =
+                fillContexts.stream().map(FillContext::getStructure).collect(toList());
+        AssistStructure latestStructure = fillContexts.get(fillContexts.size() - 1).getStructure();
+        ClientParser parser = new ClientParser(structures);
+        mLocalAutofillDataSource.getFieldTypeByAutofillHints(
+                new DataCallback<HashMap<String, FieldTypeWithHeuristics>>() {
+                    @Override
+                    public void onLoaded(
+                            HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint) {
+                        mAutofillDataBuilder = new ClientAutofillDataBuilder(
+                                fieldTypesByAutofillHint, getPackageName(), parser);
+                        ClientViewMetadataBuilder clientViewMetadataBuilder =
+                                new ClientViewMetadataBuilder(parser, fieldTypesByAutofillHint);
+                        mClientViewMetadata = clientViewMetadataBuilder.buildClientViewMetadata();
+                        String packageName = latestStructure.getActivityComponent().getPackageName();
+                        if (!mPackageVerificationRepository.putPackageSignatures(packageName)) {
+                            callback.onFailure(getString(R.string.invalid_package_signature));
+                            return;
+                        }
+                        if (logVerboseEnabled()) {
+                            logv("onSaveRequest(): clientState=%s",
+                                    bundleToString(request.getClientState()));
+                        }
+                        dumpStructure(latestStructure);
+                        checkWebDomainAndBuildAutofillData(packageName, callback);
+                    }
+
+                    @Override
+                    public void onDataNotAvailable(String msg, Object... params) {
+                        loge("Should not happen - could not find field types.");
+                    }
+                });
+    }
+
+    private void checkWebDomainAndBuildAutofillData(String packageName, SaveCallback callback) {
+        String webDomain;
+        try {
+            webDomain = mClientViewMetadata.getWebDomain();
+        } catch (SecurityException e) {
+            logw(e.getMessage());
+            callback.onFailure(getString(R.string.security_exception));
+            return;
+        }
+        if (webDomain != null && webDomain.length() > 0) {
+            DalCheckRequirement req = mPreferences.getDalCheckRequirement();
+            mDalRepository.checkValid(req, new DalInfo(webDomain, packageName),
+                    new DataCallback<DalCheck>() {
+                        @Override
+                        public void onLoaded(DalCheck dalCheck) {
+                            if (dalCheck.linked) {
+                                logd("Domain %s is valid for %s", webDomain, packageName);
+                                buildAndSaveAutofillData();
+                            } else {
+                                loge("Could not associate web domain %s with app %s",
+                                        webDomain, packageName);
+                                callback.onFailure(getString(R.string.dal_exception));
+                            }
+                        }
+
+                        @Override
+                        public void onDataNotAvailable(String msg, Object... params) {
+                            logw(msg, params);
+                            callback.onFailure(getString(R.string.dal_exception));
+                        }
+                    });
+        } else {
+            logd("no web domain");
+            buildAndSaveAutofillData();
+        }
+    }
+
+    private void buildAndSaveAutofillData() {
+        int datasetNumber = mLocalAutofillDataSource.getDatasetNumber();
+        List<DatasetWithFilledAutofillFields> datasetsWithFilledAutofillFields =
+                mAutofillDataBuilder.buildDatasetsByPartition(datasetNumber);
+        mLocalAutofillDataSource.saveAutofillDatasets(datasetsWithFilledAutofillFields);
+    }
+
+    @Override
+    public void onConnected() {
+        logd("onConnected");
+    }
+
+    @Override
+    public void onDisconnected() {
+        logd("onDisconnected");
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/RemoteViewsHelper.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/RemoteViewsHelper.java
new file mode 100644
index 0000000..b925b95
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/RemoteViewsHelper.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.example.android.autofill.service;
+
+import android.support.annotation.DrawableRes;
+import android.widget.RemoteViews;
+
+/**
+ * This is a class containing helper methods for building Autofill Datasets and Responses.
+ */
+public final class RemoteViewsHelper {
+    private RemoteViewsHelper() {
+    }
+
+    public static RemoteViews viewsWithAuth(String packageName, String text) {
+        return simpleRemoteViews(packageName, text, R.drawable.ic_lock_black_24dp);
+    }
+
+    public static RemoteViews viewsWithNoAuth(String packageName, String text) {
+        return simpleRemoteViews(packageName, text, R.drawable.ic_person_black_24dp);
+    }
+
+    private static RemoteViews simpleRemoteViews(String packageName, String remoteViewsText,
+            @DrawableRes int drawableId) {
+        RemoteViews presentation = new RemoteViews(packageName,
+                R.layout.multidataset_service_list_item);
+        presentation.setTextViewText(R.id.text, remoteViewsText);
+        presentation.setImageViewResource(R.id.icon, drawableId);
+        return presentation;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/W3cHints.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/W3cHints.java
new file mode 100644
index 0000000..fd8e945
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/W3cHints.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.example.android.autofill.service;
+
+public final class W3cHints {
+    // Optional W3C prefixes
+    public static final String PREFIX_SECTION = "section-";
+    public static final String SHIPPING = "shipping";
+    public static final String BILLING = "billing";
+    // W3C prefixes below...
+    public static final String PREFIX_HOME = "home";
+    public static final String PREFIX_WORK = "work";
+    public static final String PREFIX_FAX = "fax";
+    public static final String PREFIX_PAGER = "pager";
+    // ... require those suffix
+    public static final String TEL = "tel";
+    public static final String TEL_COUNTRY_CODE = "tel-country-code";
+    public static final String TEL_NATIONAL = "tel-national";
+    public static final String TEL_AREA_CODE = "tel-area-code";
+    public static final String TEL_LOCAL = "tel-local";
+    public static final String TEL_LOCAL_PREFIX = "tel-local-prefix";
+    public static final String TEL_LOCAL_SUFFIX = "tel-local-suffix";
+    public static final String TEL_EXTENSION = "tel_extension";
+    public static final String EMAIL = "email";
+    public static final String IMPP = "impp";
+
+    private W3cHints() {
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/AutofillDataBuilder.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/AutofillDataBuilder.java
new file mode 100644
index 0000000..0110bdd
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/AutofillDataBuilder.java
@@ -0,0 +1,25 @@
+/*
+ * 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 com.example.android.autofill.service.data;
+
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+
+import java.util.List;
+
+public interface AutofillDataBuilder {
+    List<DatasetWithFilledAutofillFields> buildDatasetsByPartition(int datasetNumber);
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientAutofillDataBuilder.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientAutofillDataBuilder.java
new file mode 100644
index 0000000..2d26833
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientAutofillDataBuilder.java
@@ -0,0 +1,160 @@
+/*
+ * 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 com.example.android.autofill.service.data;
+
+import android.app.assist.AssistStructure;
+import android.support.annotation.NonNull;
+import android.view.View;
+import android.view.autofill.AutofillValue;
+
+import com.example.android.autofill.service.AutofillHints;
+import com.example.android.autofill.service.ClientParser;
+import com.example.android.autofill.service.model.AutofillDataset;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.model.FilledAutofillField;
+import com.google.common.collect.ImmutableList;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import static com.example.android.autofill.service.util.Util.loge;
+
+public class ClientAutofillDataBuilder implements AutofillDataBuilder {
+    private final ClientParser mClientParser;
+    private final HashMap<String, FieldTypeWithHeuristics> mFieldTypesByAutofillHint;
+    private final String mPackageName;
+
+    public ClientAutofillDataBuilder(HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint,
+            String packageName, ClientParser clientParser) {
+        mClientParser = clientParser;
+        mFieldTypesByAutofillHint = fieldTypesByAutofillHint;
+        mPackageName = packageName;
+    }
+
+    @Override
+    public List<DatasetWithFilledAutofillFields> buildDatasetsByPartition(int datasetNumber) {
+        ImmutableList.Builder<DatasetWithFilledAutofillFields> listBuilder =
+                new ImmutableList.Builder<>();
+        for (int partition : AutofillHints.PARTITIONS) {
+            AutofillDataset autofillDataset = new AutofillDataset(UUID.randomUUID().toString(),
+                    "dataset-" + datasetNumber + "." + partition, mPackageName);
+            DatasetWithFilledAutofillFields dataset =
+                    buildDatasetForPartition(autofillDataset, partition);
+            if (dataset != null && dataset.filledAutofillFields != null) {
+                listBuilder.add(dataset);
+            }
+        }
+        return listBuilder.build();
+    }
+
+    /**
+     * Parses a client view structure and build a dataset (in the form of a
+     * {@link DatasetWithFilledAutofillFields}) from the view metadata found.
+     */
+    private DatasetWithFilledAutofillFields buildDatasetForPartition(AutofillDataset dataset,
+            int partition) {
+        DatasetWithFilledAutofillFields datasetWithFilledAutofillFields =
+                new DatasetWithFilledAutofillFields();
+        datasetWithFilledAutofillFields.autofillDataset = dataset;
+        mClientParser.parse((node) ->
+                parseAutofillFields(node, datasetWithFilledAutofillFields, partition)
+        );
+        return datasetWithFilledAutofillFields;
+
+    }
+
+    private void parseAutofillFields(AssistStructure.ViewNode viewNode,
+            DatasetWithFilledAutofillFields datasetWithFilledAutofillFields, int partition) {
+        String[] hints = viewNode.getAutofillHints();
+        if (hints == null || hints.length == 0) {
+            return;
+        }
+        AutofillValue autofillValue = viewNode.getAutofillValue();
+        String textValue = null;
+        Long dateValue = null;
+        Boolean toggleValue = null;
+        CharSequence[] autofillOptions = null;
+        Integer listIndex = null;
+        if (autofillValue != null) {
+            if (autofillValue.isText()) {
+                // Using toString of AutofillValue.getTextValue in order to save it to
+                // SharedPreferences.
+                textValue = autofillValue.getTextValue().toString();
+            } else if (autofillValue.isDate()) {
+                dateValue = autofillValue.getDateValue();
+            } else if (autofillValue.isList()) {
+                autofillOptions = viewNode.getAutofillOptions();
+                listIndex = autofillValue.getListValue();
+            } else if (autofillValue.isToggle()) {
+                toggleValue = autofillValue.getToggleValue();
+            }
+        }
+        appendViewMetadata(datasetWithFilledAutofillFields,
+                hints, partition, textValue, dateValue, toggleValue,
+                autofillOptions, listIndex);
+    }
+
+    private void appendViewMetadata(@NonNull DatasetWithFilledAutofillFields
+            datasetWithFilledAutofillFields, @NonNull String[] hints, int partition,
+            @Nullable String textValue, @Nullable Long dateValue, @Nullable Boolean toggleValue,
+            @Nullable CharSequence[] autofillOptions, @Nullable Integer listIndex) {
+        for (int i = 0; i < hints.length; i++) {
+            String hint = hints[i];
+            // Then check if the "actual" hint is supported.
+            FieldTypeWithHeuristics fieldTypeWithHeuristics = mFieldTypesByAutofillHint.get(hint);
+            if (fieldTypeWithHeuristics != null) {
+                FieldType fieldType = fieldTypeWithHeuristics.fieldType;
+                if (!AutofillHints.matchesPartition(fieldType.getPartition(), partition)) {
+                    continue;
+                }
+                    // Only add the field if the hint is supported by the type.
+                if (textValue != null) {
+                        if (!fieldType.getAutofillTypes().ints.contains(View.AUTOFILL_TYPE_TEXT)) {
+                            loge("Text is invalid type for hint '%s'", hint);
+                        }
+                    }
+                if (autofillOptions != null && listIndex != null &&
+                        autofillOptions.length > listIndex) {
+                    if (!fieldType.getAutofillTypes().ints.contains(View.AUTOFILL_TYPE_LIST)) {
+                        loge("List is invalid type for hint '%s'", hint);
+                    }
+                    textValue = autofillOptions[listIndex].toString();
+                }
+                if (dateValue != null) {
+                    if (!fieldType.getAutofillTypes().ints.contains(View.AUTOFILL_TYPE_DATE)) {
+                        loge("Date is invalid type for hint '%s'", hint);
+                    }
+                }
+                if (toggleValue != null) {
+                    if (!fieldType.getAutofillTypes().ints.contains(View.AUTOFILL_TYPE_TOGGLE)) {
+                        loge("Toggle is invalid type for hint '%s'", hint);
+                    }
+                }
+                String datasetId = datasetWithFilledAutofillFields.autofillDataset.getId();
+                datasetWithFilledAutofillFields.add(new FilledAutofillField(datasetId,
+                        fieldType.getTypeName(), textValue, dateValue, toggleValue));
+            } else {
+                loge("Invalid hint: %s", hint);
+            }
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadata.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadata.java
new file mode 100644
index 0000000..85b789e
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadata.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.example.android.autofill.service.data;
+
+import android.service.autofill.SaveInfo;
+import android.view.autofill.AutofillId;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * In this simple implementation, the only view data we collect from the client are autofill hints
+ * of the views in the view hierarchy, the corresponding autofill IDs, and the {@link SaveInfo}
+ * based on the hints.
+ */
+public class ClientViewMetadata {
+    private final List<String> mAllHints;
+    private final int mSaveType;
+    private final AutofillId[] mAutofillIds;
+    private final String mWebDomain;
+    private final AutofillId[] mFocusedIds;
+
+    public ClientViewMetadata(List<String> allHints, int saveType, AutofillId[] autofillIds,
+            AutofillId[] focusedIds, String webDomain) {
+        mAllHints = allHints;
+        mSaveType = saveType;
+        mAutofillIds = autofillIds;
+        mWebDomain = webDomain;
+        mFocusedIds = focusedIds;
+    }
+
+    public List<String> getAllHints() {
+        return mAllHints;
+    }
+
+    public AutofillId[] getAutofillIds() {
+        return mAutofillIds;
+    }
+
+    public AutofillId[] getFocusedIds() {
+        return mFocusedIds;
+    }
+
+    public int getSaveType() {
+        return mSaveType;
+    }
+
+    public String getWebDomain() {
+        return mWebDomain;
+    }
+
+    @Override public String toString() {
+        return "ClientViewMetadata{" +
+                "mAllHints=" + mAllHints +
+                ", mSaveType=" + mSaveType +
+                ", mAutofillIds=" + Arrays.toString(mAutofillIds) +
+                ", mWebDomain='" + mWebDomain + '\'' +
+                ", mFocusedIds=" + Arrays.toString(mFocusedIds) +
+                '}';
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java
new file mode 100644
index 0000000..40a67ef
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.example.android.autofill.service.data;
+
+
+import android.app.assist.AssistStructure;
+import android.util.MutableInt;
+import android.view.autofill.AutofillId;
+
+import com.example.android.autofill.service.ClientParser;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static com.example.android.autofill.service.util.Util.logd;
+
+public class ClientViewMetadataBuilder {
+    private ClientParser mClientParser;
+    private HashMap<String, FieldTypeWithHeuristics> mFieldTypesByAutofillHint;
+
+    public ClientViewMetadataBuilder(ClientParser parser,
+            HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint) {
+        mClientParser = parser;
+        mFieldTypesByAutofillHint = fieldTypesByAutofillHint;
+    }
+
+    public ClientViewMetadata buildClientViewMetadata() {
+        List<String> allHints = new ArrayList<>();
+        MutableInt saveType = new MutableInt(0);
+        List<AutofillId> autofillIds = new ArrayList<>();
+        StringBuilder webDomainBuilder = new StringBuilder();
+        List<AutofillId> focusedAutofillIds = new ArrayList<>();
+        mClientParser.parse((node) -> parseNode(node, allHints, saveType, autofillIds, focusedAutofillIds));
+        mClientParser.parse((node) -> parseWebDomain(node, webDomainBuilder));
+        String webDomain = webDomainBuilder.toString();
+        AutofillId[] autofillIdsArray = autofillIds.toArray(new AutofillId[autofillIds.size()]);
+        AutofillId[] focusedIds = focusedAutofillIds.toArray(new AutofillId[focusedAutofillIds.size()]);
+        return new ClientViewMetadata(allHints, saveType.value, autofillIdsArray, focusedIds, webDomain);
+    }
+
+    private void parseWebDomain(AssistStructure.ViewNode viewNode, StringBuilder validWebDomain) {
+        String webDomain = viewNode.getWebDomain();
+        if (webDomain != null) {
+            logd("child web domain: %s", webDomain);
+            if (validWebDomain.length() > 0) {
+                if (!webDomain.equals(validWebDomain.toString())) {
+                    throw new SecurityException("Found multiple web domains: valid= "
+                            + validWebDomain + ", child=" + webDomain);
+                }
+            } else {
+                validWebDomain.append(webDomain);
+            }
+        }
+    }
+
+    private void parseNode(AssistStructure.ViewNode root, List<String> allHints,
+            MutableInt autofillSaveType, List<AutofillId> autofillIds,
+            List<AutofillId> focusedAutofillIds) {
+        String[] hints = root.getAutofillHints();
+        if (hints != null) {
+            for (String hint : hints) {
+                FieldTypeWithHeuristics fieldTypeWithHints = mFieldTypesByAutofillHint.get(hint);
+                if (fieldTypeWithHints != null && fieldTypeWithHints.fieldType != null) {
+                    allHints.add(hint);
+                    autofillSaveType.value |= fieldTypeWithHints.fieldType.getSaveInfo();
+                    autofillIds.add(root.getAutofillId());
+                }
+            }
+        }
+        if (root.isFocused()) {
+            focusedAutofillIds.add(root.getAutofillId());
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/DataCallback.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/DataCallback.java
new file mode 100644
index 0000000..e765602
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/DataCallback.java
@@ -0,0 +1,23 @@
+/*
+ * 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 com.example.android.autofill.service.data;
+
+public interface DataCallback<T> {
+    void onLoaded(T object);
+
+    void onDataNotAvailable(String msg, Object... params);
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/FakeAutofillDataBuilder.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/FakeAutofillDataBuilder.java
new file mode 100644
index 0000000..67ee880
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/FakeAutofillDataBuilder.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.example.android.autofill.service.data;
+
+import com.example.android.autofill.service.AutofillHints;
+import com.example.android.autofill.service.model.AutofillDataset;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.model.FilledAutofillField;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.UUID;
+
+public class FakeAutofillDataBuilder implements AutofillDataBuilder {
+    private final List<FieldTypeWithHeuristics> mFieldTypesWithHints;
+    private final String mPackageName;
+    private final int mSeed;
+
+    public FakeAutofillDataBuilder(List<FieldTypeWithHeuristics> fieldTypesWithHints,
+            String packageName, int seed) {
+        mFieldTypesWithHints = fieldTypesWithHints;
+        mSeed = seed;
+        mPackageName = packageName;
+    }
+
+    @Override
+    public List<DatasetWithFilledAutofillFields> buildDatasetsByPartition(int datasetNumber) {
+        ImmutableList.Builder<DatasetWithFilledAutofillFields> listBuilder =
+                new ImmutableList.Builder<>();
+        for (int partition : AutofillHints.PARTITIONS) {
+            AutofillDataset autofillDataset = new AutofillDataset(UUID.randomUUID().toString(),
+                    "dataset-" + datasetNumber + "." + partition, mPackageName);
+            DatasetWithFilledAutofillFields datasetWithFilledAutofillFields =
+                    buildCollectionForPartition(autofillDataset, partition);
+            if (datasetWithFilledAutofillFields != null &&
+                    datasetWithFilledAutofillFields.filledAutofillFields != null &&
+                    !datasetWithFilledAutofillFields.filledAutofillFields.isEmpty()) {
+                listBuilder.add(datasetWithFilledAutofillFields);
+            }
+        }
+        return listBuilder.build();
+    }
+
+    private DatasetWithFilledAutofillFields buildCollectionForPartition(
+            AutofillDataset dataset, int partition) {
+        DatasetWithFilledAutofillFields datasetWithFilledAutofillFields =
+                new DatasetWithFilledAutofillFields();
+        datasetWithFilledAutofillFields.autofillDataset = dataset;
+        for (FieldTypeWithHeuristics fieldTypeWithHeuristics : mFieldTypesWithHints) {
+            if (AutofillHints.matchesPartition(
+                    fieldTypeWithHeuristics.getFieldType().getPartition(), partition)) {
+                FilledAutofillField fakeField =
+                        AutofillHints.generateFakeField(fieldTypeWithHeuristics, mPackageName,
+                                mSeed, dataset.getId());
+                datasetWithFilledAutofillFields.add(fakeField);
+            }
+        }
+        return datasetWithFilledAutofillFields;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/DatasetAdapter.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/DatasetAdapter.java
new file mode 100644
index 0000000..6f7e603
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/DatasetAdapter.java
@@ -0,0 +1,189 @@
+/*
+ * 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 com.example.android.autofill.service.data.adapter;
+
+import android.app.assist.AssistStructure;
+import android.content.IntentSender;
+import android.service.autofill.Dataset;
+import android.util.MutableBoolean;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.widget.RemoteViews;
+
+import com.example.android.autofill.service.AutofillHints;
+import com.example.android.autofill.service.ClientParser;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.model.FilledAutofillField;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+import static com.example.android.autofill.service.util.Util.indexOf;
+import static com.example.android.autofill.service.util.Util.logv;
+import static com.example.android.autofill.service.util.Util.logw;
+import static java.util.stream.Collectors.toMap;
+
+public class DatasetAdapter {
+    private final ClientParser mClientParser;
+
+    public DatasetAdapter(ClientParser clientParser) {
+        mClientParser = clientParser;
+    }
+
+    /**
+     * Wraps autofill data in a {@link Dataset} object which can then be sent back to the client.
+     */
+    public Dataset buildDataset(HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint,
+            DatasetWithFilledAutofillFields datasetWithFilledAutofillFields,
+            RemoteViews remoteViews) {
+        return buildDataset(fieldTypesByAutofillHint, datasetWithFilledAutofillFields, remoteViews,
+                null);
+    }
+
+    public Dataset buildDatasetForFocusedNode(FilledAutofillField filledAutofillField,
+            FieldType fieldType, RemoteViews remoteViews) {
+        Dataset.Builder datasetBuilder = new Dataset.Builder(remoteViews);
+        boolean setAtLeastOneValue = bindDatasetToFocusedNode(filledAutofillField,
+                fieldType, datasetBuilder);
+        if (!setAtLeastOneValue) {
+            return null;
+        }
+        return datasetBuilder.build();
+    }
+
+    /**
+     * Wraps autofill data in a {@link Dataset} object with an IntentSender, which can then be
+     * sent back to the client.
+     */
+    public Dataset buildDataset(HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint,
+            DatasetWithFilledAutofillFields datasetWithFilledAutofillFields,
+            RemoteViews remoteViews, IntentSender intentSender) {
+        Dataset.Builder datasetBuilder = new Dataset.Builder(remoteViews);
+        if (intentSender != null) {
+            datasetBuilder.setAuthentication(intentSender);
+        }
+        boolean setAtLeastOneValue = bindDataset(fieldTypesByAutofillHint,
+                datasetWithFilledAutofillFields, datasetBuilder);
+        if (!setAtLeastOneValue) {
+            return null;
+        }
+        return datasetBuilder.build();
+    }
+
+    /**
+     * Build an autofill {@link Dataset} using saved data and the client's AssistStructure.
+     */
+    private boolean bindDataset(HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint,
+            DatasetWithFilledAutofillFields datasetWithFilledAutofillFields,
+            Dataset.Builder datasetBuilder) {
+        MutableBoolean setValueAtLeastOnce = new MutableBoolean(false);
+        Map<String, FilledAutofillField> filledAutofillFieldsByTypeName =
+                datasetWithFilledAutofillFields.filledAutofillFields.stream()
+                        .collect(toMap(FilledAutofillField::getFieldTypeName, Function.identity()));
+        mClientParser.parse((node) ->
+                parseAutofillFields(node, fieldTypesByAutofillHint, filledAutofillFieldsByTypeName,
+                        datasetBuilder, setValueAtLeastOnce)
+        );
+        return setValueAtLeastOnce.value;
+    }
+
+    private boolean bindDatasetToFocusedNode(FilledAutofillField field,
+            FieldType fieldType, Dataset.Builder builder) {
+        MutableBoolean setValueAtLeastOnce = new MutableBoolean(false);
+        mClientParser.parse((node) -> {
+            if (node.isFocused() && node.getAutofillId() != null) {
+                bindValueToNode(node, field, builder, setValueAtLeastOnce);
+            }
+        });
+        return setValueAtLeastOnce.value;
+    }
+
+    private void parseAutofillFields(AssistStructure.ViewNode viewNode,
+            HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint,
+            Map<String, FilledAutofillField> filledAutofillFieldsByTypeName,
+            Dataset.Builder builder, MutableBoolean setValueAtLeastOnce) {
+        String[] rawHints = viewNode.getAutofillHints();
+        if (rawHints == null || rawHints.length == 0) {
+            logv("No af hints at ViewNode - %s", viewNode.getIdEntry());
+            return;
+        }
+        String fieldTypeName = AutofillHints.getFieldTypeNameFromAutofillHints(
+                fieldTypesByAutofillHint, Arrays.asList(rawHints));
+        if (fieldTypeName == null) {
+            return;
+        }
+        FilledAutofillField field = filledAutofillFieldsByTypeName.get(fieldTypeName);
+        if (field == null) {
+            return;
+        }
+        bindValueToNode(viewNode, field, builder, setValueAtLeastOnce);
+    }
+
+    void bindValueToNode(AssistStructure.ViewNode viewNode,
+            FilledAutofillField field, Dataset.Builder builder,
+            MutableBoolean setValueAtLeastOnce) {
+        AutofillId autofillId = viewNode.getAutofillId();
+        if (autofillId == null) {
+            logw("Autofill ID null for %s", viewNode.toString());
+            return;
+        }
+        int autofillType = viewNode.getAutofillType();
+        switch (autofillType) {
+            case View.AUTOFILL_TYPE_LIST:
+                CharSequence[] options = viewNode.getAutofillOptions();
+                int listValue = -1;
+                if (options != null) {
+                    listValue = indexOf(viewNode.getAutofillOptions(), field.getTextValue());
+                }
+                if (listValue != -1) {
+                    builder.setValue(autofillId, AutofillValue.forList(listValue));
+                    setValueAtLeastOnce.value = true;
+                }
+                break;
+            case View.AUTOFILL_TYPE_DATE:
+                Long dateValue = field.getDateValue();
+                if (dateValue != null) {
+                    builder.setValue(autofillId, AutofillValue.forDate(dateValue));
+                    setValueAtLeastOnce.value = true;
+                }
+                break;
+            case View.AUTOFILL_TYPE_TEXT:
+                String textValue = field.getTextValue();
+                if (textValue != null) {
+                    builder.setValue(autofillId, AutofillValue.forText(textValue));
+                    setValueAtLeastOnce.value = true;
+                }
+                break;
+            case View.AUTOFILL_TYPE_TOGGLE:
+                Boolean toggleValue = field.getToggleValue();
+                if (toggleValue != null) {
+                    builder.setValue(autofillId, AutofillValue.forToggle(toggleValue));
+                    setValueAtLeastOnce.value = true;
+                }
+                break;
+            case View.AUTOFILL_TYPE_NONE:
+            default:
+                logw("Invalid autofill type - %d", autofillType);
+                break;
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java
new file mode 100644
index 0000000..0300fed
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java
@@ -0,0 +1,136 @@
+/*
+ * 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 com.example.android.autofill.service.data.adapter;
+
+import android.content.Context;
+import android.content.IntentSender;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.service.autofill.SaveInfo;
+import android.view.autofill.AutofillId;
+import android.widget.RemoteViews;
+
+import com.example.android.autofill.service.AuthActivity;
+import com.example.android.autofill.service.RemoteViewsHelper;
+import com.example.android.autofill.service.data.ClientViewMetadata;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.model.FilledAutofillField;
+
+import java.util.HashMap;
+import java.util.List;
+
+public class ResponseAdapter {
+    private final Context mContext;
+    private final DatasetAdapter mDatasetAdapter;
+    private final String mPackageName;
+    private final ClientViewMetadata mClientViewMetadata;
+
+    public ResponseAdapter(Context context, ClientViewMetadata clientViewMetadata,
+            String packageName, DatasetAdapter datasetAdapter) {
+        mContext = context;
+        mClientViewMetadata = clientViewMetadata;
+        mDatasetAdapter = datasetAdapter;
+        mPackageName = packageName;
+    }
+
+    public FillResponse buildResponseForFocusedNode(String datasetName, FilledAutofillField field,
+            FieldType fieldType) {
+        FillResponse.Builder responseBuilder = new FillResponse.Builder();
+        RemoteViews remoteViews = RemoteViewsHelper.viewsWithNoAuth(
+                mPackageName, datasetName);
+        Dataset dataset = mDatasetAdapter.buildDatasetForFocusedNode(field, fieldType, remoteViews);
+        if (dataset != null) {
+            responseBuilder.addDataset(dataset);
+            return responseBuilder.build();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Wraps autofill data in a Response object (essentially a series of Datasets) which can then
+     * be sent back to the client View.
+     */
+    public FillResponse buildResponse(HashMap<String, FieldTypeWithHeuristics> fieldTypesByAutofillHint,
+            List<DatasetWithFilledAutofillFields> datasets, boolean datasetAuth) {
+        FillResponse.Builder responseBuilder = new FillResponse.Builder();
+        if (datasets != null) {
+            for (DatasetWithFilledAutofillFields datasetWithFilledAutofillFields : datasets) {
+                if (datasetWithFilledAutofillFields != null) {
+                    Dataset dataset;
+                    String datasetName = datasetWithFilledAutofillFields.autofillDataset
+                            .getDatasetName();
+                    if (datasetAuth) {
+                        IntentSender intentSender = AuthActivity.getAuthIntentSenderForDataset(
+                                mContext, datasetName);
+                        RemoteViews remoteViews = RemoteViewsHelper.viewsWithAuth(
+                                mPackageName, datasetName);
+                        dataset = mDatasetAdapter.buildDataset(fieldTypesByAutofillHint,
+                                datasetWithFilledAutofillFields, remoteViews, intentSender);
+                    } else {
+                        RemoteViews remoteViews = RemoteViewsHelper.viewsWithNoAuth(
+                                mPackageName, datasetName);
+                        dataset = mDatasetAdapter.buildDataset(fieldTypesByAutofillHint,
+                                datasetWithFilledAutofillFields, remoteViews);
+                    }
+                    if (dataset != null) {
+                        responseBuilder.addDataset(dataset);
+                    }
+                }
+            }
+        }
+        int saveType = mClientViewMetadata.getSaveType();
+        AutofillId[] autofillIds = mClientViewMetadata.getAutofillIds();
+        if (autofillIds != null && autofillIds.length > 0) {
+            SaveInfo saveInfo = new SaveInfo.Builder(saveType, autofillIds).build();
+            responseBuilder.setSaveInfo(saveInfo);
+            return responseBuilder.build();
+        } else {
+            return null;
+        }
+    }
+
+    public FillResponse buildResponse(IntentSender sender, RemoteViews remoteViews) {
+        FillResponse.Builder responseBuilder = new FillResponse.Builder();
+        int saveType = mClientViewMetadata.getSaveType();
+        AutofillId[] autofillIds = mClientViewMetadata.getAutofillIds();
+        if (autofillIds != null && autofillIds.length > 0) {
+            SaveInfo saveInfo = new SaveInfo.Builder(saveType, autofillIds).build();
+            responseBuilder.setSaveInfo(saveInfo);
+            responseBuilder.setAuthentication(autofillIds, sender, remoteViews);
+            return responseBuilder.build();
+        } else {
+            return null;
+        }
+    }
+
+    public FillResponse buildManualResponse(IntentSender sender, RemoteViews remoteViews) {
+        FillResponse.Builder responseBuilder = new FillResponse.Builder();
+        int saveType = mClientViewMetadata.getSaveType();
+        AutofillId[] focusedIds = mClientViewMetadata.getFocusedIds();
+        if (focusedIds != null && focusedIds.length > 0) {
+            SaveInfo saveInfo = new SaveInfo.Builder(saveType, focusedIds).build();
+            return responseBuilder.setSaveInfo(saveInfo)
+                    .setAuthentication(focusedIds, sender, remoteViews)
+                    .build();
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/AutofillDataSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/AutofillDataSource.java
new file mode 100644
index 0000000..e3579dd
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/AutofillDataSource.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.example.android.autofill.service.data.source;
+
+import com.example.android.autofill.service.data.DataCallback;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.model.FilledAutofillField;
+import com.example.android.autofill.service.model.ResourceIdHeuristic;
+
+import java.util.HashMap;
+import java.util.List;
+
+public interface AutofillDataSource {
+
+    /**
+     * Asynchronously gets saved list of {@link DatasetWithFilledAutofillFields} that contains some
+     * objects that can autofill fields with these {@code autofillHints}.
+     */
+    void getAutofillDatasets(List<String> allAutofillHints,
+            DataCallback<List<DatasetWithFilledAutofillFields>> datasetsCallback);
+
+    void getAllAutofillDatasets(
+            DataCallback<List<DatasetWithFilledAutofillFields>> datasetsCallback);
+
+    /**
+     * Asynchronously gets a saved {@link DatasetWithFilledAutofillFields} for a specific
+     * {@code datasetName} that contains some objects that can autofill fields with these
+     * {@code autofillHints}.
+     */
+    void getAutofillDataset(List<String> allAutofillHints,
+            String datasetName, DataCallback<DatasetWithFilledAutofillFields> datasetsCallback);
+
+    /**
+     * Stores a collection of Autofill fields.
+     */
+    void saveAutofillDatasets(List<DatasetWithFilledAutofillFields>
+            datasetsWithFilledAutofillFields);
+
+    void saveResourceIdHeuristic(ResourceIdHeuristic resourceIdHeuristic);
+
+    /**
+     * Gets all autofill field types.
+     */
+    void getFieldTypes(DataCallback<List<FieldTypeWithHeuristics>> fieldTypesCallback);
+
+    /**
+     * Gets all autofill field types.
+     */
+    void getFieldType(String typeName, DataCallback<FieldType> fieldTypeCallback);
+
+    void getFieldTypeByAutofillHints(
+            DataCallback<HashMap<String, FieldTypeWithHeuristics>> fieldTypeMapCallback);
+
+    void getFilledAutofillField(String datasetId, String fieldTypeName, DataCallback<FilledAutofillField> fieldCallback);
+
+    /**
+     * Clears all data.
+     */
+    void clear();
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DalService.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DalService.java
new file mode 100644
index 0000000..b9cf695
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DalService.java
@@ -0,0 +1,31 @@
+/*
+ * 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 com.example.android.autofill.service.data.source;
+
+import com.example.android.autofill.service.model.DalCheck;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+public interface DalService {
+    @GET("/v1/assetlinks:check")
+    Call<DalCheck> check(@Query("source.web.site") String webDomain,
+            @Query("relation") String permission,
+            @Query("target.android_app.package_name") String packageName,
+            @Query("target.android_app.certificate.sha256_fingerprint") String fingerprint);
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DefaultFieldTypesSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DefaultFieldTypesSource.java
new file mode 100644
index 0000000..22cbead
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DefaultFieldTypesSource.java
@@ -0,0 +1,25 @@
+/*
+ * 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.example.android.autofill.service.data.source;
+
+import com.example.android.autofill.service.model.DefaultFieldTypeWithHints;
+
+import java.util.List;
+
+public interface DefaultFieldTypesSource {
+    List<DefaultFieldTypeWithHints> getDefaultFieldTypes();
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DigitalAssetLinksDataSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DigitalAssetLinksDataSource.java
new file mode 100644
index 0000000..00661a7
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DigitalAssetLinksDataSource.java
@@ -0,0 +1,40 @@
+/*
+ * 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 com.example.android.autofill.service.data.source;
+
+import com.example.android.autofill.service.data.DataCallback;
+import com.example.android.autofill.service.model.DalCheck;
+import com.example.android.autofill.service.model.DalInfo;
+
+import static com.example.android.autofill.service.util.Util.DalCheckRequirement;
+
+/**
+ * Data source for
+ * <a href="https://developers.google.com/digital-asset-links/">Digital Asset Links</a>.
+ */
+public interface DigitalAssetLinksDataSource {
+
+    /**
+     * Checks if the association between a web domain and a package is valid.
+     */
+    void checkValid(DalCheckRequirement dalCheckRequirement, DalInfo dalInfo,
+            DataCallback<DalCheck> dalCheckCallback);
+
+    /**
+     * Clears all cached data.
+     */
+    void clear();
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/PackageVerificationDataSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/PackageVerificationDataSource.java
new file mode 100644
index 0000000..7e271e0
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/PackageVerificationDataSource.java
@@ -0,0 +1,36 @@
+/*
+ * 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 com.example.android.autofill.service.data.source;
+
+public interface PackageVerificationDataSource {
+
+    /**
+     * Verifies that the signatures in the passed {@code Context} match what is currently in
+     * storage. If there are no current signatures in storage for this packageName, it will store
+     * the signatures from the passed {@code Context}.
+     *
+     * @return {@code true} if signatures for this packageName are not currently in storage
+     * or if the signatures in the passed {@code Context} match what is currently in storage;
+     * {@code false} if the signatures in the passed {@code Context} do not match what is
+     * currently in storage or if an {@code Exception} was thrown while generating the signatures.
+     */
+    boolean putPackageSignatures(String packageName);
+
+    /**
+     * Clears all signature data currently in storage.
+     */
+    void clear();
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DefaultFieldTypesLocalJsonSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DefaultFieldTypesLocalJsonSource.java
new file mode 100644
index 0000000..d403f32
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DefaultFieldTypesLocalJsonSource.java
@@ -0,0 +1,68 @@
+/*
+ * 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.example.android.autofill.service.data.source.local;
+
+import android.content.res.Resources;
+
+import com.example.android.autofill.service.R;
+import com.example.android.autofill.service.data.source.DefaultFieldTypesSource;
+import com.example.android.autofill.service.model.DefaultFieldTypeWithHints;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.lang.reflect.Type;
+import java.util.List;
+
+import static com.example.android.autofill.service.util.Util.loge;
+
+public class DefaultFieldTypesLocalJsonSource implements DefaultFieldTypesSource {
+    private static DefaultFieldTypesLocalJsonSource sInstance;
+
+    private final Resources mResources;
+    private final Gson mGson;
+
+    private DefaultFieldTypesLocalJsonSource(Resources resources, Gson gson) {
+        mResources = resources;
+        mGson = gson;
+    }
+
+    public static DefaultFieldTypesLocalJsonSource getInstance(Resources resources, Gson gson) {
+        if (sInstance == null) {
+            sInstance = new DefaultFieldTypesLocalJsonSource(resources, gson);
+        }
+        return sInstance;
+    }
+
+    @Override
+    public List<DefaultFieldTypeWithHints> getDefaultFieldTypes() {
+        Type fieldTypeListType =  TypeToken.getParameterized(List.class,
+                DefaultFieldTypeWithHints.class).getType();
+        InputStream is = mResources.openRawResource(R.raw.default_field_types);
+        List<DefaultFieldTypeWithHints> fieldTypes = null;
+        try(Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
+            fieldTypes = mGson.fromJson(reader, fieldTypeListType);
+        } catch (IOException e) {
+            loge(e, "Exception during deserialization of FieldTypes.");
+        }
+        return fieldTypes;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DigitalAssetLinksRepository.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DigitalAssetLinksRepository.java
new file mode 100644
index 0000000..6303a1e
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DigitalAssetLinksRepository.java
@@ -0,0 +1,159 @@
+/*
+ * 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 com.example.android.autofill.service.data.source.local;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.support.annotation.NonNull;
+
+import com.example.android.autofill.service.data.DataCallback;
+import com.example.android.autofill.service.data.source.DalService;
+import com.example.android.autofill.service.data.source.DigitalAssetLinksDataSource;
+import com.example.android.autofill.service.model.DalCheck;
+import com.example.android.autofill.service.model.DalInfo;
+import com.example.android.autofill.service.util.SecurityHelper;
+import com.google.common.net.InternetDomainName;
+
+import java.util.HashMap;
+
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+
+import static com.example.android.autofill.service.util.Util.DalCheckRequirement;
+import static com.example.android.autofill.service.util.Util.DalCheckRequirement.AllUrls;
+import static com.example.android.autofill.service.util.Util.DalCheckRequirement.Disabled;
+import static com.example.android.autofill.service.util.Util.DalCheckRequirement.LoginOnly;
+import static com.example.android.autofill.service.util.Util.logd;
+
+
+/**
+ * Singleton repository that caches the result of Digital Asset Links checks.
+ */
+public class DigitalAssetLinksRepository implements DigitalAssetLinksDataSource {
+    private static final String DAL_BASE_URL = "https://digitalassetlinks.googleapis.com";
+    private static final String PERMISSION_GET_LOGIN_CREDS = "common.get_login_creds";
+    private static final String PERMISSION_HANDLE_ALL_URLS = "common.handle_all_urls";
+    private static DigitalAssetLinksRepository sInstance;
+
+    private final PackageManager mPackageManager;
+    private final DalService mDalService;
+    private final HashMap<DalInfo, DalCheck> mCache;
+
+    private DigitalAssetLinksRepository(PackageManager packageManager) {
+        mPackageManager = packageManager;
+        mCache = new HashMap<>();
+        mDalService = new Retrofit.Builder()
+                .baseUrl(DAL_BASE_URL)
+                .build()
+                .create(DalService.class);
+    }
+
+    public static DigitalAssetLinksRepository getInstance(PackageManager packageManager) {
+        if (sInstance == null) {
+            sInstance = new DigitalAssetLinksRepository(packageManager);
+        }
+        return sInstance;
+    }
+
+    public static String getCanonicalDomain(String domain) {
+        InternetDomainName idn = InternetDomainName.from(domain);
+        while (idn != null && !idn.isTopPrivateDomain()) {
+            idn = idn.parent();
+        }
+        return idn == null ? null : idn.toString();
+    }
+
+    @Override
+    public void clear() {
+        mCache.clear();
+    }
+
+    public void checkValid(DalCheckRequirement dalCheckRequirement, DalInfo dalInfo,
+            DataCallback<DalCheck> dalCheckDataCallback) {
+        if (dalCheckRequirement.equals(Disabled)) {
+            DalCheck dalCheck = new DalCheck();
+            dalCheck.linked = true;
+            dalCheckDataCallback.onLoaded(dalCheck);
+            return;
+        }
+
+        DalCheck dalCheck = mCache.get(dalInfo);
+        if (dalCheck != null) {
+            dalCheckDataCallback.onLoaded(dalCheck);
+            return;
+        }
+        String packageName = dalInfo.getPackageName();
+        String webDomain = dalInfo.getWebDomain();
+
+        final String fingerprint;
+        try {
+            PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
+                    PackageManager.GET_SIGNATURES);
+            fingerprint = SecurityHelper.getFingerprint(packageInfo, packageName);
+        } catch (Exception e) {
+            dalCheckDataCallback.onDataNotAvailable("Error getting fingerprint for %s",
+                    packageName);
+            return;
+        }
+        logd("validating domain %s for pkg %s and fingerprint %s.", webDomain,
+                packageName, fingerprint);
+        mDalService.check(webDomain, PERMISSION_GET_LOGIN_CREDS, packageName, fingerprint).enqueue(
+                new Callback<DalCheck>() {
+                    @Override
+                    public void onResponse(@NonNull Call<DalCheck> call,
+                            @NonNull Response<DalCheck> response) {
+                        DalCheck dalCheck = response.body();
+                        if (dalCheck == null || !dalCheck.linked) {
+                            // get_login_creds check failed, so try handle_all_urls check
+                            if (dalCheckRequirement.equals(LoginOnly)) {
+                                dalCheckDataCallback.onDataNotAvailable(
+                                        "DAL: Login creds check failed.");
+                            } else if (dalCheckRequirement.equals(AllUrls)) {
+                                mDalService.check(webDomain, PERMISSION_HANDLE_ALL_URLS,
+                                        packageName, fingerprint).enqueue(new Callback<DalCheck>() {
+                                    @Override
+                                    public void onResponse(@NonNull Call<DalCheck> call,
+                                            @NonNull Response<DalCheck> response) {
+                                        DalCheck dalCheck = response.body();
+                                        mCache.put(dalInfo, dalCheck);
+                                        dalCheckDataCallback.onLoaded(dalCheck);
+                                    }
+
+                                    @Override
+                                    public void onFailure(@NonNull Call<DalCheck> call,
+                                            @NonNull Throwable t) {
+                                        dalCheckDataCallback.onDataNotAvailable(t.getMessage());
+                                    }
+                                });
+                            }
+                        } else {
+                            // get_login_creds check succeeded, so we're finished.
+                            mCache.put(dalInfo, dalCheck);
+                            dalCheckDataCallback.onLoaded(dalCheck);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(@NonNull Call<DalCheck> call, @NonNull Throwable t) {
+                        // get_login_creds check failed, so try handle_all_urls check.
+                        mDalService.check(webDomain, PERMISSION_HANDLE_ALL_URLS, packageName,
+                                fingerprint);
+                    }
+                });
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/LocalAutofillDataSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/LocalAutofillDataSource.java
new file mode 100644
index 0000000..e58e18b
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/LocalAutofillDataSource.java
@@ -0,0 +1,257 @@
+/*
+ * 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 com.example.android.autofill.service.data.source.local;
+
+import android.content.SharedPreferences;
+import android.service.autofill.Dataset;
+
+import com.example.android.autofill.service.data.DataCallback;
+import com.example.android.autofill.service.data.source.AutofillDataSource;
+import com.example.android.autofill.service.data.source.local.dao.AutofillDao;
+import com.example.android.autofill.service.model.AutofillDataset;
+import com.example.android.autofill.service.model.AutofillHint;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.model.FilledAutofillField;
+import com.example.android.autofill.service.model.ResourceIdHeuristic;
+import com.example.android.autofill.service.util.AppExecutors;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.example.android.autofill.service.util.Util.logw;
+
+public class LocalAutofillDataSource implements AutofillDataSource {
+    public static final String SHARED_PREF_KEY = "com.example.android.autofill"
+            + ".service.datasource.LocalAutofillDataSource";
+    private static final String DATASET_NUMBER_KEY = "datasetNumber";
+    private static final Object sLock = new Object();
+
+    private static LocalAutofillDataSource sInstance;
+
+    private final AutofillDao mAutofillDao;
+    private final SharedPreferences mSharedPreferences;
+    private final AppExecutors mAppExecutors;
+
+    private LocalAutofillDataSource(SharedPreferences sharedPreferences, AutofillDao autofillDao,
+            AppExecutors appExecutors) {
+        mSharedPreferences = sharedPreferences;
+        mAutofillDao = autofillDao;
+        mAppExecutors = appExecutors;
+    }
+
+    public static LocalAutofillDataSource getInstance(SharedPreferences sharedPreferences,
+            AutofillDao autofillDao, AppExecutors appExecutors) {
+        synchronized (sLock) {
+            if (sInstance == null) {
+                sInstance = new LocalAutofillDataSource(sharedPreferences, autofillDao,
+                        appExecutors);
+            }
+            return sInstance;
+        }
+    }
+
+    public static void clearInstance() {
+        synchronized (sLock) {
+            sInstance = null;
+        }
+    }
+
+    @Override
+    public void getAutofillDatasets(List<String> allAutofillHints,
+            DataCallback<List<DatasetWithFilledAutofillFields>> datasetsCallback) {
+        mAppExecutors.diskIO().execute(() -> {
+            final List<String> typeNames = getFieldTypesForAutofillHints(allAutofillHints)
+                    .stream()
+                    .map(FieldTypeWithHeuristics::getFieldType)
+                    .map(FieldType::getTypeName)
+                    .collect(Collectors.toList());
+            List<DatasetWithFilledAutofillFields> datasetsWithFilledAutofillFields =
+                    mAutofillDao.getDatasets(typeNames);
+            mAppExecutors.mainThread().execute(() ->
+                    datasetsCallback.onLoaded(datasetsWithFilledAutofillFields)
+            );
+        });
+    }
+
+    @Override
+    public void getAllAutofillDatasets(
+            DataCallback<List<DatasetWithFilledAutofillFields>> datasetsCallback) {
+        mAppExecutors.diskIO().execute(() -> {
+            List<DatasetWithFilledAutofillFields> datasetsWithFilledAutofillFields =
+                    mAutofillDao.getAllDatasets();
+            mAppExecutors.mainThread().execute(() ->
+                    datasetsCallback.onLoaded(datasetsWithFilledAutofillFields)
+            );
+        });
+    }
+
+    @Override
+    public void getAutofillDataset(List<String> allAutofillHints, String datasetName,
+            DataCallback<DatasetWithFilledAutofillFields> datasetsCallback) {
+        mAppExecutors.diskIO().execute(() -> {
+            // Room does not support TypeConverters for collections.
+            List<DatasetWithFilledAutofillFields> autofillDatasetFields =
+                    mAutofillDao.getDatasetsWithName(allAutofillHints, datasetName);
+            if (autofillDatasetFields != null && !autofillDatasetFields.isEmpty()) {
+                if (autofillDatasetFields.size() > 1) {
+                    logw("More than 1 dataset with name %s", datasetName);
+                }
+                DatasetWithFilledAutofillFields dataset = autofillDatasetFields.get(0);
+
+                mAppExecutors.mainThread().execute(() ->
+                        datasetsCallback.onLoaded(dataset)
+                );
+            } else {
+                mAppExecutors.mainThread().execute(() ->
+                        datasetsCallback.onDataNotAvailable("No data found.")
+                );
+            }
+        });
+    }
+
+
+    @Override
+    public void saveAutofillDatasets(List<DatasetWithFilledAutofillFields>
+            datasetsWithFilledAutofillFields) {
+        mAppExecutors.diskIO().execute(() -> {
+            for (DatasetWithFilledAutofillFields datasetWithFilledAutofillFields :
+                    datasetsWithFilledAutofillFields) {
+                List<FilledAutofillField> filledAutofillFields =
+                        datasetWithFilledAutofillFields.filledAutofillFields;
+                AutofillDataset autofillDataset = datasetWithFilledAutofillFields.autofillDataset;
+                mAutofillDao.insertAutofillDataset(autofillDataset);
+                mAutofillDao.insertFilledAutofillFields(filledAutofillFields);
+            }
+        });
+        incrementDatasetNumber();
+    }
+
+    @Override
+    public void saveResourceIdHeuristic(ResourceIdHeuristic resourceIdHeuristic) {
+        mAppExecutors.diskIO().execute(() -> {
+            mAutofillDao.insertResourceIdHeuristic(resourceIdHeuristic);
+        });
+    }
+
+    @Override
+    public void getFieldTypes(DataCallback<List<FieldTypeWithHeuristics>> fieldTypesCallback) {
+        mAppExecutors.diskIO().execute(() -> {
+            List<FieldTypeWithHeuristics> fieldTypeWithHints = mAutofillDao.getFieldTypesWithHints();
+            mAppExecutors.mainThread().execute(() -> {
+                if (fieldTypeWithHints != null) {
+                    fieldTypesCallback.onLoaded(fieldTypeWithHints);
+                } else {
+                    fieldTypesCallback.onDataNotAvailable("Field Types not found.");
+                }
+            });
+        });
+    }
+
+    @Override
+    public void getFieldTypeByAutofillHints(
+            DataCallback<HashMap<String, FieldTypeWithHeuristics>> fieldTypeMapCallback) {
+        mAppExecutors.diskIO().execute(() -> {
+            HashMap<String, FieldTypeWithHeuristics> hintMap = getFieldTypeByAutofillHints();
+            mAppExecutors.mainThread().execute(() -> {
+                if (hintMap != null) {
+                    fieldTypeMapCallback.onLoaded(hintMap);
+                } else {
+                    fieldTypeMapCallback.onDataNotAvailable("FieldTypes not found");
+                }
+            });
+        });
+    }
+
+    @Override
+    public void getFilledAutofillField(String datasetId, String fieldTypeName, DataCallback<FilledAutofillField> fieldCallback) {
+        mAppExecutors.diskIO().execute(() -> {
+            FilledAutofillField filledAutofillField = mAutofillDao.getFilledAutofillField(datasetId, fieldTypeName);
+            mAppExecutors.mainThread().execute(() -> {
+                fieldCallback.onLoaded(filledAutofillField);
+            });
+        });
+    }
+
+    @Override
+    public void getFieldType(String fieldTypeName, DataCallback<FieldType> fieldTypeCallback) {
+        mAppExecutors.diskIO().execute(() -> {
+            FieldType fieldType = mAutofillDao.getFieldType(fieldTypeName);
+            mAppExecutors.mainThread().execute(() -> {
+                fieldTypeCallback.onLoaded(fieldType);
+            });
+        });
+    }
+
+    public void getAutofillDatasetWithId(String datasetId,
+            DataCallback<DatasetWithFilledAutofillFields> callback) {
+        mAppExecutors.diskIO().execute(() -> {
+            DatasetWithFilledAutofillFields dataset =
+                    mAutofillDao.getAutofillDatasetWithId(datasetId);
+            mAppExecutors.mainThread().execute(() -> {
+                callback.onLoaded(dataset);
+            });
+        });
+    }
+
+    private HashMap<String, FieldTypeWithHeuristics> getFieldTypeByAutofillHints() {
+        HashMap<String, FieldTypeWithHeuristics> hintMap = new HashMap<>();
+        List<FieldTypeWithHeuristics> fieldTypeWithHints =
+                mAutofillDao.getFieldTypesWithHints();
+        if (fieldTypeWithHints != null) {
+            for (FieldTypeWithHeuristics fieldType : fieldTypeWithHints) {
+                for (AutofillHint hint : fieldType.autofillHints) {
+                    hintMap.put(hint.mAutofillHint, fieldType);
+                }
+            }
+            return hintMap;
+        } else {
+            return null;
+        }
+    }
+
+    private List<FieldTypeWithHeuristics> getFieldTypesForAutofillHints(List<String> autofillHints) {
+        return mAutofillDao.getFieldTypesForAutofillHints(autofillHints);
+    }
+
+    @Override
+    public void clear() {
+        mAppExecutors.diskIO().execute(() -> {
+            mAutofillDao.clearAll();
+            mSharedPreferences.edit().putInt(DATASET_NUMBER_KEY, 0).apply();
+        });
+    }
+
+    /**
+     * For simplicity, {@link Dataset}s will be named in the form {@code dataset-X.P} where
+     * {@code X} means this was the Xth group of datasets saved, and {@code P} refers to the dataset
+     * partition number. This method returns the appropriate {@code X}.
+     */
+    public int getDatasetNumber() {
+        return mSharedPreferences.getInt(DATASET_NUMBER_KEY, 0);
+    }
+
+    /**
+     * Every time a dataset is saved, this should be called to increment the dataset number.
+     * (only important for this service's dataset naming scheme).
+     */
+    private void incrementDatasetNumber() {
+        mSharedPreferences.edit().putInt(DATASET_NUMBER_KEY, getDatasetNumber() + 1).apply();
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/SharedPrefsPackageVerificationRepository.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/SharedPrefsPackageVerificationRepository.java
new file mode 100644
index 0000000..0d43c1f
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/SharedPrefsPackageVerificationRepository.java
@@ -0,0 +1,86 @@
+/*
+ * 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 com.example.android.autofill.service.data.source.local;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+
+import com.example.android.autofill.service.data.source.PackageVerificationDataSource;
+import com.example.android.autofill.service.util.SecurityHelper;
+
+import static com.example.android.autofill.service.util.Util.logd;
+import static com.example.android.autofill.service.util.Util.logw;
+
+public class SharedPrefsPackageVerificationRepository implements PackageVerificationDataSource {
+
+    private static final String SHARED_PREF_KEY = "com.example.android.autofill.service"
+            + ".datasource.PackageVerificationDataSource";
+    private static PackageVerificationDataSource sInstance;
+
+    private final SharedPreferences mSharedPrefs;
+    private final Context mContext;
+
+    private SharedPrefsPackageVerificationRepository(Context context) {
+        mSharedPrefs = context.getApplicationContext()
+                .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE);
+        mContext = context.getApplicationContext();
+    }
+
+    public static PackageVerificationDataSource getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new SharedPrefsPackageVerificationRepository(
+                    context.getApplicationContext());
+        }
+        return sInstance;
+    }
+
+    @Override
+    public void clear() {
+        mSharedPrefs.edit().clear().apply();
+    }
+
+    @Override
+    public boolean putPackageSignatures(String packageName) {
+        String hash;
+        try {
+            PackageManager pm = mContext.getPackageManager();
+            PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+            hash = SecurityHelper.getFingerprint(packageInfo, packageName);
+            logd("Hash for %s: %s", packageName, hash);
+        } catch (Exception e) {
+            logw(e, "Error getting hash for %s.", packageName);
+            return false;
+        }
+
+        if (!containsSignatureForPackage(packageName)) {
+            // Storage does not yet contain signature for this package name.
+            mSharedPrefs.edit().putString(packageName, hash).apply();
+            return true;
+        }
+        return containsMatchingSignatureForPackage(packageName, hash);
+    }
+
+    private boolean containsSignatureForPackage(String packageName) {
+        return mSharedPrefs.contains(packageName);
+    }
+
+    private boolean containsMatchingSignatureForPackage(String packageName,
+            String hash) {
+        return hash.equals(mSharedPrefs.getString(packageName, null));
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/dao/AutofillDao.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/dao/AutofillDao.java
new file mode 100644
index 0000000..084532c
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/dao/AutofillDao.java
@@ -0,0 +1,126 @@
+/*
+ * 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 com.example.android.autofill.service.data.source.local.dao;
+
+import android.arch.persistence.room.Dao;
+import android.arch.persistence.room.Insert;
+import android.arch.persistence.room.OnConflictStrategy;
+import android.arch.persistence.room.Query;
+
+import com.example.android.autofill.service.model.AutofillDataset;
+import com.example.android.autofill.service.model.AutofillHint;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.model.FilledAutofillField;
+import com.example.android.autofill.service.model.ResourceIdHeuristic;
+
+import java.util.Collection;
+import java.util.List;
+
+@Dao
+public interface AutofillDao {
+    /**
+     * Fetches a list of datasets associated to autofill fields on the page.
+     *
+     * @param allAutofillHints Filtering parameter; represents all of the hints associated with
+     *                         all of the views on the page.
+     */
+    @Query("SELECT DISTINCT id, datasetName FROM FilledAutofillField, AutofillDataset" +
+            " WHERE AutofillDataset.id = FilledAutofillField.datasetId" +
+            " AND FilledAutofillField.fieldTypeName IN (:allAutofillHints)")
+    List<DatasetWithFilledAutofillFields> getDatasets(List<String> allAutofillHints);
+
+    @Query("SELECT DISTINCT id, datasetName FROM FilledAutofillField, AutofillDataset" +
+            " WHERE AutofillDataset.id = FilledAutofillField.datasetId")
+    List<DatasetWithFilledAutofillFields> getAllDatasets();
+
+    /**
+     * Fetches a list of datasets associated to autofill fields. It should only return a dataset
+     * if that dataset has an autofill field associate with the view the user is focused on, and
+     * if that dataset's name matches the name passed in.
+     *
+     * @param fieldTypes Filtering parameter; represents all of the field types associated with
+     *                         all of the views on the page.
+     * @param datasetName      Filtering parameter; only return datasets with this name.
+     */
+    @Query("SELECT DISTINCT id, datasetName FROM FilledAutofillField, AutofillDataset" +
+            " WHERE AutofillDataset.id = FilledAutofillField.datasetId" +
+            " AND AutofillDataset.datasetName = (:datasetName)" +
+            " AND FilledAutofillField.fieldTypeName IN (:fieldTypes)")
+    List<DatasetWithFilledAutofillFields> getDatasetsWithName(
+            List<String> fieldTypes, String datasetName);
+
+    @Query("SELECT DISTINCT typeName, autofillTypes, saveInfo, partition, strictExampleSet, " +
+            "textTemplate, dateTemplate" +
+            " FROM FieldType, AutofillHint" +
+            " WHERE FieldType.typeName = AutofillHint.fieldTypeName" +
+            " UNION " +
+            "SELECT DISTINCT typeName, autofillTypes, saveInfo, partition, strictExampleSet, " +
+            "textTemplate, dateTemplate" +
+            " FROM FieldType, ResourceIdHeuristic" +
+            " WHERE FieldType.typeName = ResourceIdHeuristic.fieldTypeName")
+    List<FieldTypeWithHeuristics> getFieldTypesWithHints();
+
+    @Query("SELECT DISTINCT typeName, autofillTypes, saveInfo, partition, strictExampleSet, " +
+            "textTemplate, dateTemplate" +
+            " FROM FieldType, AutofillHint" +
+            " WHERE FieldType.typeName = AutofillHint.fieldTypeName" +
+            " AND AutofillHint.autofillHint IN (:autofillHints)" +
+            " UNION " +
+            "SELECT DISTINCT typeName, autofillTypes, saveInfo, partition, strictExampleSet, " +
+            "textTemplate, dateTemplate" +
+            " FROM FieldType, ResourceIdHeuristic" +
+            " WHERE FieldType.typeName = ResourceIdHeuristic.fieldTypeName")
+    List<FieldTypeWithHeuristics> getFieldTypesForAutofillHints(List<String> autofillHints);
+
+    @Query("SELECT DISTINCT id, datasetName FROM FilledAutofillField, AutofillDataset" +
+            " WHERE AutofillDataset.id = FilledAutofillField.datasetId" +
+            " AND AutofillDataset.id = (:datasetId)")
+    DatasetWithFilledAutofillFields getAutofillDatasetWithId(String datasetId);
+
+    @Query("SELECT * FROM FilledAutofillField" +
+            " WHERE FilledAutofillField.datasetId = (:datasetId)" +
+            " AND FilledAutofillField.fieldTypeName = (:fieldTypeName)")
+    FilledAutofillField getFilledAutofillField(String datasetId, String fieldTypeName);
+
+    @Query("SELECT * FROM FieldType" +
+            " WHERE FieldType.typeName = (:fieldTypeName)")
+    FieldType getFieldType(String fieldTypeName);
+
+    /**
+     * @param autofillFields Collection of autofill fields to be saved to the db.
+     */
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    void insertFilledAutofillFields(Collection<FilledAutofillField> autofillFields);
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    void insertAutofillDataset(AutofillDataset datasets);
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    void insertAutofillHints(List<AutofillHint> autofillHints);
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    void insertResourceIdHeuristic(ResourceIdHeuristic resourceIdHeuristic);
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    void insertFieldTypes(List<FieldType> fieldTypes);
+
+
+    @Query("DELETE FROM AutofillDataset")
+    void clearAll();
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/AutofillDatabase.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/AutofillDatabase.java
new file mode 100644
index 0000000..fe007ce
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/AutofillDatabase.java
@@ -0,0 +1,114 @@
+/*
+ * 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 com.example.android.autofill.service.data.source.local.db;
+
+import android.arch.persistence.db.SupportSQLiteDatabase;
+import android.arch.persistence.room.Database;
+import android.arch.persistence.room.Room;
+import android.arch.persistence.room.RoomDatabase;
+import android.arch.persistence.room.TypeConverters;
+import android.content.Context;
+import android.support.annotation.NonNull;
+
+import com.example.android.autofill.service.data.source.DefaultFieldTypesSource;
+import com.example.android.autofill.service.data.source.local.dao.AutofillDao;
+import com.example.android.autofill.service.model.AutofillDataset;
+import com.example.android.autofill.service.model.AutofillHint;
+import com.example.android.autofill.service.model.DefaultFieldTypeWithHints;
+import com.example.android.autofill.service.model.FakeData;
+import com.example.android.autofill.service.model.FieldType;
+import com.example.android.autofill.service.model.FilledAutofillField;
+import com.example.android.autofill.service.model.ResourceIdHeuristic;
+import com.example.android.autofill.service.util.AppExecutors;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.example.android.autofill.service.data.source.local.db.Converters.IntList;
+import static java.util.stream.Collectors.toList;
+
+@Database(entities = {
+        FilledAutofillField.class,
+        AutofillDataset.class,
+        FieldType.class,
+        AutofillHint.class,
+        ResourceIdHeuristic.class
+}, version = 1)
+@TypeConverters({Converters.class})
+public abstract class AutofillDatabase extends RoomDatabase {
+
+    private static final Object sLock = new Object();
+    private static AutofillDatabase sInstance;
+
+    public static AutofillDatabase getInstance(Context context,
+            DefaultFieldTypesSource defaultFieldTypesSource,
+            AppExecutors appExecutors) {
+        if (sInstance == null) {
+            synchronized (sLock) {
+                if (sInstance == null) {
+                    sInstance = Room.databaseBuilder(context.getApplicationContext(),
+                            AutofillDatabase.class, "AutofillSample.db")
+                            .addCallback(new RoomDatabase.Callback() {
+                                @Override
+                                public void onCreate(@NonNull SupportSQLiteDatabase db) {
+                                    appExecutors.diskIO().execute(() -> {
+                                        List<DefaultFieldTypeWithHints> fieldTypes =
+                                                defaultFieldTypesSource.getDefaultFieldTypes();
+                                        AutofillDatabase autofillDatabase =
+                                                getInstance(context, defaultFieldTypesSource,
+                                                        appExecutors);
+                                        autofillDatabase.saveDefaultFieldTypes(fieldTypes);
+                                    });
+                                }
+
+                                @Override
+                                public void onOpen(@NonNull SupportSQLiteDatabase db) {
+                                    super.onOpen(db);
+                                }
+                            })
+                            .build();
+                }
+            }
+        }
+        return sInstance;
+    }
+
+    private void saveDefaultFieldTypes(List<DefaultFieldTypeWithHints> defaultFieldTypes) {
+        List<FieldType> storedFieldTypes = new ArrayList<>();
+        List<AutofillHint> storedAutofillHints = new ArrayList<>();
+        for (DefaultFieldTypeWithHints defaultType : defaultFieldTypes) {
+            DefaultFieldTypeWithHints.DefaultFieldType defaultFieldType = defaultType.fieldType;
+            List<String> autofillHints = defaultType.autofillHints;
+            IntList autofillTypes = new IntList(defaultFieldType.autofillTypes);
+            DefaultFieldTypeWithHints.DefaultFakeData defaultFakeData = defaultType.fieldType.fakeData;
+            FakeData fakeData = new FakeData(new Converters.StringList(
+                    defaultFakeData.strictExampleSet), defaultFakeData.textTemplate,
+                    defaultFakeData.dateTemplate);
+            FieldType storedFieldType = new FieldType(defaultFieldType.typeName, autofillTypes,
+                    defaultFieldType.saveInfo, defaultFieldType.partition, fakeData);
+            storedFieldTypes.add(storedFieldType);
+            storedAutofillHints.addAll(autofillHints.stream()
+                    .map((autofillHint) -> new AutofillHint(autofillHint,
+                            storedFieldType.getTypeName())).collect(toList()));
+        }
+        AutofillDao autofillDao = autofillDao();
+        autofillDao.insertFieldTypes(storedFieldTypes);
+        autofillDao.insertAutofillHints(storedAutofillHints);
+    }
+
+    public abstract AutofillDao autofillDao();
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/Converters.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/Converters.java
new file mode 100644
index 0000000..2829f8b
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/Converters.java
@@ -0,0 +1,100 @@
+/*
+ * 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 com.example.android.autofill.service.data.source.local.db;
+
+import android.arch.persistence.room.TypeConverter;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * Type converter for Room database.
+ */
+public class Converters {
+
+    /**
+     * If database returns a {@link String} containing a comma delimited list of ints, this converts
+     * the {@link String} to an {@link IntList}.
+     */
+    @TypeConverter
+    public static IntList storedStringToIntList(String value) {
+        List<String> strings = Arrays.asList(value.split("\\s*,\\s*"));
+        List<Integer> ints = strings.stream().map(Integer::parseInt).collect(toList());
+        return new IntList(ints);
+    }
+
+    /**
+     * Converts the {@link IntList} back into a String containing a comma delimited list of
+     * ints.
+     */
+    @TypeConverter
+    public static String intListToStoredString(IntList list) {
+        StringBuilder stringBuilder = new StringBuilder();
+        for (Integer integer : list.ints) {
+            stringBuilder.append(integer).append(",");
+        }
+        return stringBuilder.toString();
+    }
+
+    /**
+     * If database returns a {@link String} containing a comma delimited list of Strings, this
+     * converts the {@link String} to a {@link StringList}.
+     */
+    @TypeConverter
+    public static StringList storedStringToStringList(String value) {
+        List<String> strings = Arrays.asList(value.split("\\s*,\\s*"));
+        return new StringList(strings);
+    }
+
+
+    /**
+     * Converts the {@link StringList} back into a {@link String} containing a comma delimited
+     * list of {@link String}s.
+     */
+    @TypeConverter
+    public static String stringListToStoredString(StringList list) {
+        StringBuilder stringBuilder = new StringBuilder();
+        for (String string : list.strings) {
+            stringBuilder.append(string).append(",");
+        }
+        return stringBuilder.toString();
+    }
+
+    /**
+     * Wrapper class for {@code List<Integer>} so it can work with Room type converters.
+     */
+    public static class IntList {
+        public final List<Integer> ints;
+
+        public IntList(List<Integer> ints) {
+            this.ints = ints;
+        }
+    }
+
+    /**
+     * Wrapper class for {@code List<String>} so it can work with Room type converters.
+     */
+    public static class StringList {
+        public final List<String> strings;
+
+        public StringList(List<String> ints) {
+            this.strings = ints;
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/AutofillDataset.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/AutofillDataset.java
new file mode 100644
index 0000000..6b6596c
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/AutofillDataset.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.example.android.autofill.service.model;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Entity;
+import android.support.annotation.NonNull;
+
+@Entity(primaryKeys = {"id"})
+public class AutofillDataset {
+    @NonNull
+    @ColumnInfo(name = "id")
+    private final String mId;
+
+    @NonNull
+    @ColumnInfo(name = "datasetName")
+    private final String mDatasetName;
+
+    @NonNull
+    @ColumnInfo(name = "packageName")
+    private final String mPackageName;
+
+    public AutofillDataset(@NonNull String id, @NonNull String datasetName,
+                           @NonNull String packageName) {
+        mId = id;
+        mDatasetName = datasetName;
+        mPackageName = packageName;
+    }
+
+    @NonNull
+    public String getId() {
+        return mId;
+    }
+
+    @NonNull
+    public String getDatasetName() {
+        return mDatasetName;
+    }
+
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AutofillDataset that = (AutofillDataset) o;
+
+        if (!mId.equals(that.mId)) return false;
+        if (!mDatasetName.equals(that.mDatasetName)) return false;
+        return mPackageName.equals(that.mPackageName);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mId.hashCode();
+        result = 31 * result + mDatasetName.hashCode();
+        result = 31 * result + mPackageName.hashCode();
+        return result;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/AutofillHint.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/AutofillHint.java
new file mode 100644
index 0000000..be4aa7d
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/AutofillHint.java
@@ -0,0 +1,41 @@
+/*
+ * 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.example.android.autofill.service.model;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.ForeignKey;
+import android.support.annotation.NonNull;
+
+@Entity(primaryKeys = {"autofillHint"}, foreignKeys = @ForeignKey(
+        entity = FieldType.class, parentColumns = "typeName", childColumns = "fieldTypeName",
+        onDelete = ForeignKey.CASCADE))
+public class AutofillHint {
+
+    @NonNull
+    @ColumnInfo(name = "autofillHint")
+    public String mAutofillHint;
+
+    @NonNull
+    @ColumnInfo(name = "fieldTypeName")
+    public String mFieldTypeName;
+
+    public AutofillHint(@NonNull String autofillHint, @NonNull String fieldTypeName) {
+        this.mAutofillHint = autofillHint;
+        this.mFieldTypeName = fieldTypeName;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DalCheck.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DalCheck.java
new file mode 100644
index 0000000..ede77ba
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DalCheck.java
@@ -0,0 +1,23 @@
+/*
+ * 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 com.example.android.autofill.service.model;
+
+public class DalCheck {
+    public boolean linked;
+    public String maxAge;
+    public String debugString;
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DalInfo.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DalInfo.java
new file mode 100644
index 0000000..44002ca
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DalInfo.java
@@ -0,0 +1,67 @@
+/*
+ * 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 com.example.android.autofill.service.model;
+
+import static com.example.android.autofill.service.data.source.local.DigitalAssetLinksRepository.getCanonicalDomain;
+
+public class DalInfo {
+    private final String mWebDomain;
+    private final String mPackageName;
+
+    public DalInfo(String webDomain, String packageName) {
+        String canonicalDomain = getCanonicalDomain(webDomain);
+        final String fullDomain;
+        if (!webDomain.startsWith("http:") && !webDomain.startsWith("https:")) {
+            // Unfortunately AssistStructure.ViewNode does not tell what the domain is, so let's
+            // assume it's https
+            fullDomain = "https://" + canonicalDomain;
+        } else {
+            fullDomain = canonicalDomain;
+        }
+        mWebDomain = fullDomain;
+        mPackageName = packageName;
+    }
+
+    public String getWebDomain() {
+        return mWebDomain;
+    }
+
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DalInfo dalInfo = (DalInfo) o;
+
+        if (mWebDomain != null ? !mWebDomain.equals(dalInfo.mWebDomain) :
+                dalInfo.mWebDomain != null)
+            return false;
+        return mPackageName != null ? mPackageName.equals(dalInfo.mPackageName) :
+                dalInfo.mPackageName == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mWebDomain != null ? mWebDomain.hashCode() : 0;
+        result = 31 * result + (mPackageName != null ? mPackageName.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DatasetWithFilledAutofillFields.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DatasetWithFilledAutofillFields.java
new file mode 100644
index 0000000..06b529f
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DatasetWithFilledAutofillFields.java
@@ -0,0 +1,60 @@
+/*
+ * 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 com.example.android.autofill.service.model;
+
+import android.arch.persistence.room.Embedded;
+import android.arch.persistence.room.Relation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DatasetWithFilledAutofillFields {
+    @Embedded
+    public AutofillDataset autofillDataset;
+
+    @Relation(parentColumn = "id", entityColumn = "datasetId", entity = FilledAutofillField.class)
+    public List<FilledAutofillField> filledAutofillFields;
+
+    public void add(FilledAutofillField filledAutofillField) {
+        if (filledAutofillFields == null) {
+            this.filledAutofillFields = new ArrayList<>();
+        }
+        this.filledAutofillFields.add(filledAutofillField);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DatasetWithFilledAutofillFields that = (DatasetWithFilledAutofillFields) o;
+
+        if (autofillDataset != null ? !autofillDataset.equals(that.autofillDataset) :
+                that.autofillDataset != null)
+            return false;
+        return filledAutofillFields != null ?
+                filledAutofillFields.equals(that.filledAutofillFields) :
+                that.filledAutofillFields == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = autofillDataset != null ? autofillDataset.hashCode() : 0;
+        result = 31 * result + (filledAutofillFields != null ? filledAutofillFields.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DefaultFieldTypeWithHints.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DefaultFieldTypeWithHints.java
new file mode 100644
index 0000000..70ad382
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DefaultFieldTypeWithHints.java
@@ -0,0 +1,73 @@
+/*
+ * 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.example.android.autofill.service.model;
+
+import java.util.List;
+
+/**
+ * JSON model class, representing an autofillable field type. It is called "Default" because only
+ * default field types will be included in the packaged JSON. After the JSON is initially read and
+ * written to the DB, the field types can be dynamically added, modified, and removed.
+ *<p>
+ * It contains all of the metadata about the field type. For example, if the field type is
+ * "country", this is the JSON object associated with it:
+ <pre class="prettyprint">
+ {
+     "autofillHints": [
+         "country"
+     ],
+     "fieldType": {
+         "autofillTypes": [
+             1,
+             3
+         ],
+         "fakeData": {
+             "strictExampleSet": [],
+             "textTemplate": "countryseed"
+         },
+         "partition": 1,
+         "saveInfo": 2,
+         "typeName": "country"
+     }
+ }
+ </pre>
+ */
+public class DefaultFieldTypeWithHints {
+    public DefaultFieldType fieldType;
+    public List<String> autofillHints;
+
+    public static class DefaultFieldType {
+        public String typeName;
+        public List<Integer> autofillTypes;
+        public int saveInfo;
+        public int partition;
+        public DefaultFakeData fakeData;
+    }
+
+    public static class DefaultFakeData {
+        public List<String> strictExampleSet;
+        public String textTemplate;
+        public String dateTemplate;
+
+        public DefaultFakeData(List<String> strictExampleSet, String textTemplate,
+                String dateTemplate) {
+            this.strictExampleSet = strictExampleSet;
+            this.textTemplate = textTemplate;
+            this.dateTemplate = dateTemplate;
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FakeData.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FakeData.java
new file mode 100644
index 0000000..5d0837b
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FakeData.java
@@ -0,0 +1,31 @@
+/*
+ * 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.example.android.autofill.service.model;
+
+import com.example.android.autofill.service.data.source.local.db.Converters;
+
+public class FakeData {
+    public Converters.StringList strictExampleSet;
+    public String textTemplate;
+    public String dateTemplate;
+
+    public FakeData(Converters.StringList strictExampleSet, String textTemplate, String dateTemplate) {
+        this.strictExampleSet = strictExampleSet;
+        this.textTemplate = textTemplate;
+        this.dateTemplate = dateTemplate;
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldType.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldType.java
new file mode 100644
index 0000000..4d285f3
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldType.java
@@ -0,0 +1,81 @@
+/*
+ * 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.example.android.autofill.service.model;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Embedded;
+import android.arch.persistence.room.Entity;
+import android.support.annotation.NonNull;
+
+import static com.example.android.autofill.service.data.source.local.db.Converters.IntList;
+
+@Entity(primaryKeys = {"typeName"})
+public class FieldType {
+    @NonNull
+    @ColumnInfo(name = "typeName")
+    private final String mTypeName;
+
+    @NonNull
+    @ColumnInfo(name = "autofillTypes")
+    private final IntList mAutofillTypes;
+
+    @NonNull
+    @ColumnInfo(name = "saveInfo")
+    private final Integer mSaveInfo;
+
+    @NonNull
+    @ColumnInfo(name = "partition")
+    private final Integer mPartition;
+
+    @NonNull
+    @Embedded
+    private final FakeData mFakeData;
+
+    public FieldType(@NonNull String typeName, @NonNull IntList autofillTypes,
+            @NonNull Integer saveInfo, @NonNull Integer partition, @NonNull FakeData fakeData) {
+        mTypeName = typeName;
+        mAutofillTypes = autofillTypes;
+        mSaveInfo = saveInfo;
+        mPartition = partition;
+        mFakeData = fakeData;
+    }
+
+    @NonNull
+    public String getTypeName() {
+        return mTypeName;
+    }
+
+    @NonNull
+    public IntList getAutofillTypes() {
+        return mAutofillTypes;
+    }
+
+    @NonNull
+    public Integer getSaveInfo() {
+        return mSaveInfo;
+    }
+
+    @NonNull
+    public Integer getPartition() {
+        return mPartition;
+    }
+
+    @NonNull
+    public FakeData getFakeData() {
+        return mFakeData;
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldTypeWithHeuristics.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldTypeWithHeuristics.java
new file mode 100644
index 0000000..97a646e
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldTypeWithHeuristics.java
@@ -0,0 +1,45 @@
+/*
+ * 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.example.android.autofill.service.model;
+
+import android.arch.persistence.room.Embedded;
+import android.arch.persistence.room.Relation;
+
+import java.util.List;
+
+public class FieldTypeWithHeuristics {
+    @Embedded
+    public FieldType fieldType;
+
+    @Relation(parentColumn = "typeName", entityColumn = "fieldTypeName", entity = AutofillHint.class)
+    public List<AutofillHint> autofillHints;
+
+    @Relation(parentColumn = "typeName", entityColumn = "fieldTypeName", entity = ResourceIdHeuristic.class)
+    public List<ResourceIdHeuristic> resourceIdHeuristics;
+
+    public FieldType getFieldType() {
+        return fieldType;
+    }
+
+    public List<AutofillHint> getAutofillHints() {
+        return autofillHints;
+    }
+
+    public List<ResourceIdHeuristic> getResourceIdHeuristics() {
+        return resourceIdHeuristics;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FilledAutofillField.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FilledAutofillField.java
new file mode 100644
index 0000000..85ad05a
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FilledAutofillField.java
@@ -0,0 +1,146 @@
+/*
+ * 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 com.example.android.autofill.service.model;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.ForeignKey;
+import android.arch.persistence.room.Ignore;
+import android.support.annotation.NonNull;
+
+import javax.annotation.Nullable;
+
+@Entity(primaryKeys = {"datasetId", "fieldTypeName"}, foreignKeys = {
+        @ForeignKey(entity = AutofillDataset.class, parentColumns = "id",
+                childColumns = "datasetId", onDelete = ForeignKey.CASCADE),
+        @ForeignKey(entity = FieldType.class, parentColumns = "typeName",
+                childColumns = "fieldTypeName", onDelete = ForeignKey.CASCADE)
+})
+public class FilledAutofillField {
+
+    @NonNull
+    @ColumnInfo(name = "datasetId")
+    private final String mDatasetId;
+
+    @Nullable
+    @ColumnInfo(name = "textValue")
+    private final String mTextValue;
+
+    @Nullable
+    @ColumnInfo(name = "dateValue")
+    private final Long mDateValue;
+
+    @Nullable
+    @ColumnInfo(name = "toggleValue")
+    private final Boolean mToggleValue;
+
+    @NonNull
+    @ColumnInfo(name = "fieldTypeName")
+    private final String mFieldTypeName;
+
+    public FilledAutofillField(@NonNull String datasetId, @NonNull String fieldTypeName,
+                               @Nullable String textValue, @Nullable Long dateValue,
+                               @Nullable Boolean toggleValue) {
+        mDatasetId = datasetId;
+        mFieldTypeName = fieldTypeName;
+        mTextValue = textValue;
+        mDateValue = dateValue;
+        mToggleValue = toggleValue;
+    }
+
+    @Ignore
+    public FilledAutofillField(@NonNull String datasetId,
+            @NonNull String fieldTypeName, @Nullable String textValue, @Nullable Long dateValue) {
+        this(datasetId, fieldTypeName, textValue, dateValue, null);
+    }
+
+    @Ignore
+    public FilledAutofillField(@NonNull String datasetId, @NonNull String fieldTypeName,
+                               @Nullable String textValue) {
+        this(datasetId, fieldTypeName, textValue, null, null);
+    }
+
+    @Ignore
+    public FilledAutofillField(@NonNull String datasetId, @NonNull String fieldTypeName,
+                               @Nullable Long dateValue) {
+        this(datasetId, fieldTypeName, null, dateValue, null);
+    }
+
+    @Ignore
+    public FilledAutofillField(@NonNull String datasetId, @NonNull String fieldTypeName,
+                               @Nullable Boolean toggleValue) {
+        this(datasetId, fieldTypeName, null, null, toggleValue);
+    }
+
+    @Ignore
+    public FilledAutofillField(@NonNull String datasetId, @NonNull String fieldTypeName) {
+        this(datasetId, fieldTypeName, null, null, null);
+    }
+
+    @NonNull
+    public String getDatasetId() {
+        return mDatasetId;
+    }
+
+    @Nullable
+    public String getTextValue() {
+        return mTextValue;
+    }
+
+    @Nullable
+    public Long getDateValue() {
+        return mDateValue;
+    }
+
+    @Nullable
+    public Boolean getToggleValue() {
+        return mToggleValue;
+    }
+
+    @NonNull
+    public String getFieldTypeName() {
+        return mFieldTypeName;
+    }
+
+    public boolean isNull() {
+        return mTextValue == null && mDateValue == null && mToggleValue == null;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        FilledAutofillField that = (FilledAutofillField) o;
+
+        if (mTextValue != null ? !mTextValue.equals(that.mTextValue) : that.mTextValue != null)
+            return false;
+        if (mDateValue != null ? !mDateValue.equals(that.mDateValue) : that.mDateValue != null)
+            return false;
+        if (mToggleValue != null ? !mToggleValue.equals(that.mToggleValue) : that.mToggleValue != null)
+            return false;
+        return mFieldTypeName.equals(that.mFieldTypeName);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mTextValue != null ? mTextValue.hashCode() : 0;
+        result = 31 * result + (mDateValue != null ? mDateValue.hashCode() : 0);
+        result = 31 * result + (mToggleValue != null ? mToggleValue.hashCode() : 0);
+        result = 31 * result + mFieldTypeName.hashCode();
+        return result;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/ResourceIdHeuristic.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/ResourceIdHeuristic.java
new file mode 100644
index 0000000..81c9abe
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/ResourceIdHeuristic.java
@@ -0,0 +1,47 @@
+/*
+ * 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.example.android.autofill.service.model;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.ForeignKey;
+import android.support.annotation.NonNull;
+
+@Entity(primaryKeys = {"resourceIdHeuristic", "packageName"}, foreignKeys = @ForeignKey(
+        entity = FieldType.class, parentColumns = "typeName", childColumns = "fieldTypeName",
+        onDelete = ForeignKey.CASCADE))
+public class ResourceIdHeuristic {
+
+    @NonNull
+    @ColumnInfo(name = "resourceIdHeuristic")
+    public String mResourceIdHeuristic;
+
+    @NonNull
+    @ColumnInfo(name = "packageName")
+    public String mPackageName;
+
+    @NonNull
+    @ColumnInfo(name = "fieldTypeName")
+    public String mFieldTypeName;
+
+    public ResourceIdHeuristic(@NonNull String resourceIdHeuristic, @NonNull String fieldTypeName,
+            @NonNull String packageName) {
+        mResourceIdHeuristic = resourceIdHeuristic;
+        mFieldTypeName = fieldTypeName;
+        mPackageName = packageName;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/MyPreferences.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/MyPreferences.java
new file mode 100644
index 0000000..8770ef8
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/MyPreferences.java
@@ -0,0 +1,110 @@
+/*
+ * 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 com.example.android.autofill.service.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.support.annotation.NonNull;
+
+import com.example.android.autofill.service.util.Util;
+
+public class MyPreferences {
+    private static final String RESPONSE_AUTH_KEY = "response_auth";
+    private static final String DATASET_AUTH_KEY = "dataset_auth";
+    private static final String MASTER_PASSWORD_KEY = "master_password";
+    private static final String LOGGING_LEVEL = "logging_level";
+    private static final String DAL_CHECK_REQUIRED = "dal_check_required";
+    private static MyPreferences sInstance;
+    private final SharedPreferences mPrefs;
+
+    private MyPreferences(Context context) {
+        mPrefs = context.getApplicationContext().getSharedPreferences("my-settings",
+                Context.MODE_PRIVATE);
+    }
+
+    public static MyPreferences getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new MyPreferences(context);
+        }
+        return sInstance;
+    }
+
+    /**
+     * Gets whether {@link FillResponse}s should require authentication.
+     */
+    public boolean isResponseAuth() {
+        return mPrefs.getBoolean(RESPONSE_AUTH_KEY, false);
+    }
+
+    /**
+     * Enables/disables authentication for the entire autofill {@link FillResponse}.
+     */
+    public void setResponseAuth(boolean responseAuth) {
+        mPrefs.edit().putBoolean(RESPONSE_AUTH_KEY, responseAuth).apply();
+    }
+
+    /**
+     * Gets whether {@link Dataset}s should require authentication.
+     */
+    public boolean isDatasetAuth() {
+        return mPrefs.getBoolean(DATASET_AUTH_KEY, false);
+    }
+
+    /**
+     * Enables/disables authentication for individual autofill {@link Dataset}s.
+     */
+    public void setDatasetAuth(boolean datasetAuth) {
+        mPrefs.edit().putBoolean(DATASET_AUTH_KEY, datasetAuth).apply();
+    }
+
+    /**
+     * Gets autofill master username.
+     */
+    public String getMasterPassword() {
+        return mPrefs.getString(MASTER_PASSWORD_KEY, null);
+    }
+
+    /**
+     * Sets autofill master password.
+     */
+    public void setMasterPassword(@NonNull String masterPassword) {
+        mPrefs.edit().putString(MASTER_PASSWORD_KEY, masterPassword).apply();
+    }
+
+    public void clearCredentials() {
+        mPrefs.edit().remove(MASTER_PASSWORD_KEY).apply();
+    }
+
+    public Util.LogLevel getLoggingLevel() {
+        return Util.LogLevel.values()[mPrefs.getInt(LOGGING_LEVEL, Util.LogLevel.Off.ordinal())];
+    }
+
+    public void setLoggingLevel(Util.LogLevel level) {
+        mPrefs.edit().putInt(LOGGING_LEVEL, level.ordinal()).apply();
+        Util.setLoggingLevel(level);
+    }
+
+    public Util.DalCheckRequirement getDalCheckRequirement() {
+        return Util.DalCheckRequirement.values()[mPrefs.getInt(DAL_CHECK_REQUIRED,
+                Util.DalCheckRequirement.AllUrls.ordinal())];
+    }
+
+    public void setDalCheckRequired(Util.DalCheckRequirement level) {
+        mPrefs.edit().putInt(DAL_CHECK_REQUIRED, level.ordinal()).apply();
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java
new file mode 100644
index 0000000..1fd87df
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java
@@ -0,0 +1,371 @@
+/*
+ * 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 com.example.android.autofill.service.settings;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.design.widget.Snackbar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.autofill.AutofillManager;
+import android.widget.CompoundButton;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.NumberPicker;
+import android.widget.RadioGroup;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.example.android.autofill.service.R;
+import com.example.android.autofill.service.data.AutofillDataBuilder;
+import com.example.android.autofill.service.data.DataCallback;
+import com.example.android.autofill.service.data.FakeAutofillDataBuilder;
+import com.example.android.autofill.service.data.source.DefaultFieldTypesSource;
+import com.example.android.autofill.service.data.source.PackageVerificationDataSource;
+import com.example.android.autofill.service.data.source.local.DefaultFieldTypesLocalJsonSource;
+import com.example.android.autofill.service.data.source.local.LocalAutofillDataSource;
+import com.example.android.autofill.service.data.source.local.SharedPrefsPackageVerificationRepository;
+import com.example.android.autofill.service.data.source.local.dao.AutofillDao;
+import com.example.android.autofill.service.data.source.local.db.AutofillDatabase;
+import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields;
+import com.example.android.autofill.service.model.FieldTypeWithHeuristics;
+import com.example.android.autofill.service.util.AppExecutors;
+import com.example.android.autofill.service.util.Util;
+import com.google.gson.GsonBuilder;
+
+import java.util.List;
+
+import static com.example.android.autofill.service.util.Util.DalCheckRequirement.AllUrls;
+import static com.example.android.autofill.service.util.Util.DalCheckRequirement.Disabled;
+import static com.example.android.autofill.service.util.Util.DalCheckRequirement.LoginOnly;
+import static com.example.android.autofill.service.util.Util.logd;
+import static com.example.android.autofill.service.util.Util.logw;
+
+public class SettingsActivity extends AppCompatActivity {
+    private static final String TAG = "SettingsActivity";
+    private static final int REQUEST_CODE_SET_DEFAULT = 1;
+    private AutofillManager mAutofillManager;
+    private LocalAutofillDataSource mLocalAutofillDataSource;
+    private PackageVerificationDataSource mPackageVerificationDataSource;
+    private MyPreferences mPreferences;
+    private String mPackageName;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.multidataset_service_settings_activity);
+        SharedPreferences localAfDataSourceSharedPrefs =
+                getSharedPreferences(LocalAutofillDataSource.SHARED_PREF_KEY, Context.MODE_PRIVATE);
+        DefaultFieldTypesSource defaultFieldTypesSource =
+                DefaultFieldTypesLocalJsonSource.getInstance(getResources(),
+                        new GsonBuilder().create());
+        AutofillDao autofillDao = AutofillDatabase.getInstance(
+                this, defaultFieldTypesSource, new AppExecutors()).autofillDao();
+        mPackageName = getPackageName();
+        mLocalAutofillDataSource = LocalAutofillDataSource.getInstance(localAfDataSourceSharedPrefs,
+                autofillDao, new AppExecutors());
+        mAutofillManager = getSystemService(AutofillManager.class);
+        mPackageVerificationDataSource =
+                SharedPrefsPackageVerificationRepository.getInstance(this);
+        mPreferences = MyPreferences.getInstance(this);
+        setupSettingsSwitch(R.id.settings_auth_responses_container,
+                R.id.settings_auth_responses_label,
+                R.id.settings_auth_responses_switch,
+                mPreferences.isResponseAuth(),
+                (compoundButton, isResponseAuth) -> mPreferences.setResponseAuth(isResponseAuth));
+        setupSettingsSwitch(R.id.settings_auth_datasets_container,
+                R.id.settings_auth_datasets_label,
+                R.id.settings_auth_datasets_switch,
+                mPreferences.isDatasetAuth(),
+                (compoundButton, isDatasetAuth) -> mPreferences.setDatasetAuth(isDatasetAuth));
+        setupSettingsButton(R.id.settings_add_data_container,
+                R.id.settings_add_data_label,
+                R.id.settings_add_data_icon,
+                (view) -> buildAddDataDialog().show());
+        setupSettingsButton(R.id.settings_clear_data_container,
+                R.id.settings_clear_data_label,
+                R.id.settings_clear_data_icon,
+                (view) -> buildClearDataDialog().show());
+        setupSettingsButton(R.id.settings_auth_credentials_container,
+                R.id.settings_auth_credentials_label,
+                R.id.settings_auth_credentials_icon,
+                (view) -> {
+                    if (mPreferences.getMasterPassword() != null) {
+                        buildCurrentCredentialsDialog().show();
+                    } else {
+                        buildNewCredentialsDialog().show();
+                    }
+                });
+        setupSettingsSwitch(R.id.settingsSetServiceContainer,
+                R.id.settingsSetServiceLabel,
+                R.id.settingsSetServiceSwitch,
+                mAutofillManager.hasEnabledAutofillServices(),
+                (compoundButton, serviceSet) -> setService(serviceSet));
+        RadioGroup loggingLevelContainer = findViewById(R.id.loggingLevelContainer);
+        Util.LogLevel loggingLevel = mPreferences.getLoggingLevel();
+        Util.setLoggingLevel(loggingLevel);
+        switch (loggingLevel) {
+            case Off:
+                loggingLevelContainer.check(R.id.loggingOff);
+                break;
+            case Debug:
+                loggingLevelContainer.check(R.id.loggingDebug);
+                break;
+            case Verbose:
+                loggingLevelContainer.check(R.id.loggingVerbose);
+                break;
+        }
+        loggingLevelContainer.setOnCheckedChangeListener((group, checkedId) -> {
+            switch (checkedId) {
+                case R.id.loggingOff:
+                    mPreferences.setLoggingLevel(Util.LogLevel.Off);
+                    break;
+                case R.id.loggingDebug:
+                    mPreferences.setLoggingLevel(Util.LogLevel.Debug);
+                    break;
+                case R.id.loggingVerbose:
+                    mPreferences.setLoggingLevel(Util.LogLevel.Verbose);
+                    break;
+            }
+        });
+        RadioGroup dalCheckRequirementContainer = findViewById(R.id.dalCheckRequirementContainer);
+        Util.DalCheckRequirement dalCheckRequirement = mPreferences.getDalCheckRequirement();
+        switch (dalCheckRequirement) {
+            case Disabled:
+                dalCheckRequirementContainer.check(R.id.dalDisabled);
+                break;
+            case LoginOnly:
+                dalCheckRequirementContainer.check(R.id.dalLoginOnly);
+                break;
+            case AllUrls:
+                dalCheckRequirementContainer.check(R.id.dalAllUrls);
+                break;
+        }
+        dalCheckRequirementContainer.setOnCheckedChangeListener((group, checkedId) -> {
+            switch (checkedId) {
+                case R.id.dalDisabled:
+                    mPreferences.setDalCheckRequired(Disabled);
+                    break;
+                case R.id.dalLoginOnly:
+                    mPreferences.setDalCheckRequired(LoginOnly);
+                    break;
+                case R.id.dalAllUrls:
+                    mPreferences.setDalCheckRequired(AllUrls);
+                    break;
+            }
+        });
+    }
+
+    private AlertDialog buildClearDataDialog() {
+        return new AlertDialog.Builder(SettingsActivity.this)
+                .setMessage(R.string.settings_clear_data_confirmation)
+                .setTitle(R.string.settings_clear_data_confirmation_title)
+                .setNegativeButton(R.string.settings_cancel, null)
+                .setPositiveButton(R.string.settings_ok, (dialog, which) -> {
+                    mLocalAutofillDataSource.clear();
+                    mPackageVerificationDataSource.clear();
+                    mPreferences.clearCredentials();
+                    dialog.dismiss();
+                })
+                .create();
+    }
+
+    private AlertDialog buildAddDataDialog() {
+        NumberPicker numberOfDatasetsPicker = LayoutInflater
+                .from(SettingsActivity.this)
+                .inflate(R.layout.multidataset_service_settings_add_data_dialog, null)
+                .findViewById(R.id.number_of_datasets_picker);
+        numberOfDatasetsPicker.setMinValue(0);
+        numberOfDatasetsPicker.setMaxValue(10);
+        numberOfDatasetsPicker.setWrapSelectorWheel(false);
+        return new AlertDialog.Builder(SettingsActivity.this)
+                .setTitle(R.string.settings_add_data_title)
+                .setNegativeButton(R.string.settings_cancel, null)
+                .setMessage(R.string.settings_select_number_of_datasets)
+                .setView(numberOfDatasetsPicker)
+                .setPositiveButton(R.string.settings_ok, (dialog, which) -> {
+                    int numOfDatasets = numberOfDatasetsPicker.getValue();
+                    mLocalAutofillDataSource.getFieldTypes(new DataCallback<List<FieldTypeWithHeuristics>>() {
+                        @Override
+                        public void onLoaded(List<FieldTypeWithHeuristics> fieldTypes) {
+                            boolean saved = buildAndSaveMockedAutofillFieldCollections(
+                                    fieldTypes, numOfDatasets);
+                            dialog.dismiss();
+                            if (saved) {
+                                Snackbar.make(findViewById(R.id.settings_layout),
+                                        getResources().getQuantityString(
+                                                R.plurals.settings_add_data_success,
+                                                numOfDatasets, numOfDatasets),
+                                        Snackbar.LENGTH_SHORT).show();
+                            }
+                        }
+
+                        @Override
+                        public void onDataNotAvailable(String msg, Object... params) {
+
+                        }
+                    });
+                })
+                .create();
+    }
+
+    public boolean buildAndSaveMockedAutofillFieldCollections(List<FieldTypeWithHeuristics> fieldTypes,
+            int numOfDatasets) {
+        if (numOfDatasets < 0 || numOfDatasets > 10) {
+            logw("Number of Datasets (%d) out of range.", numOfDatasets);
+        }
+        for (int i = 0; i < numOfDatasets; i++) {
+            int datasetNumber = mLocalAutofillDataSource.getDatasetNumber();
+            AutofillDataBuilder autofillDataBuilder =
+                    new FakeAutofillDataBuilder(fieldTypes, mPackageName, datasetNumber);
+            List<DatasetWithFilledAutofillFields> datasetsWithFilledAutofillFields =
+                    autofillDataBuilder.buildDatasetsByPartition(datasetNumber);
+            // Save datasets to database.
+            mLocalAutofillDataSource.saveAutofillDatasets(datasetsWithFilledAutofillFields);
+        }
+        return true;
+    }
+
+    private AlertDialog.Builder prepareCredentialsDialog() {
+        return new AlertDialog.Builder(SettingsActivity.this)
+                .setTitle(R.string.settings_auth_change_credentials_title)
+                .setNegativeButton(R.string.settings_cancel, null);
+    }
+
+    private AlertDialog buildCurrentCredentialsDialog() {
+        final EditText currentPasswordField = LayoutInflater
+                .from(SettingsActivity.this)
+                .inflate(R.layout.multidataset_service_settings_authentication_dialog, null)
+                .findViewById(R.id.master_password_field);
+        return prepareCredentialsDialog()
+                .setMessage(R.string.settings_auth_enter_current_password)
+                .setView(currentPasswordField)
+                .setPositiveButton(R.string.settings_ok, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        String password = currentPasswordField.getText().toString();
+                        if (mPreferences.getMasterPassword()
+                                .equals(password)) {
+                            buildNewCredentialsDialog().show();
+                            dialog.dismiss();
+                        }
+                    }
+                })
+                .create();
+    }
+
+    private AlertDialog buildNewCredentialsDialog() {
+        final EditText newPasswordField = LayoutInflater
+                .from(SettingsActivity.this)
+                .inflate(R.layout.multidataset_service_settings_authentication_dialog, null)
+                .findViewById(R.id.master_password_field);
+        return prepareCredentialsDialog()
+                .setMessage(R.string.settings_auth_enter_new_password)
+                .setView(newPasswordField)
+                .setPositiveButton(R.string.settings_ok, (dialog, which) -> {
+                    String password = newPasswordField.getText().toString();
+                    mPreferences.setMasterPassword(password);
+                    dialog.dismiss();
+                })
+                .create();
+    }
+
+    private void setupSettingsSwitch(int containerId, int labelId, int switchId, boolean checked,
+            CompoundButton.OnCheckedChangeListener checkedChangeListener) {
+        ViewGroup container = findViewById(containerId);
+        String switchLabel = ((TextView) container.findViewById(labelId)).getText().toString();
+        final Switch switchView = container.findViewById(switchId);
+        switchView.setContentDescription(switchLabel);
+        switchView.setChecked(checked);
+        container.setOnClickListener((view) -> switchView.performClick());
+        switchView.setOnCheckedChangeListener(checkedChangeListener);
+    }
+
+    private void setupSettingsButton(int containerId, int labelId, int imageViewId,
+            final View.OnClickListener onClickListener) {
+        ViewGroup container = findViewById(containerId);
+        TextView buttonLabel = container.findViewById(labelId);
+        String buttonLabelText = buttonLabel.getText().toString();
+        ImageView imageView = container.findViewById(imageViewId);
+        imageView.setContentDescription(buttonLabelText);
+        container.setOnClickListener(onClickListener);
+    }
+
+    private void setService(boolean enableService) {
+        if (enableService) {
+            startEnableService();
+        } else {
+            disableService();
+        }
+    }
+
+    private void disableService() {
+        if (mAutofillManager != null && mAutofillManager.hasEnabledAutofillServices()) {
+            mAutofillManager.disableAutofillServices();
+            Snackbar.make(findViewById(R.id.settings_layout),
+                    R.string.settings_autofill_disabled_message, Snackbar.LENGTH_SHORT).show();
+        } else {
+            logd("Sample service already disabled.");
+        }
+    }
+
+    private void startEnableService() {
+        if (mAutofillManager != null && !mAutofillManager.hasEnabledAutofillServices()) {
+            Intent intent = new Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE);
+            intent.setData(Uri.parse("package:com.example.android.autofill.service"));
+            logd(TAG, "enableService(): intent=%s", intent);
+            startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT);
+        } else {
+            logd("Sample service already enabled.");
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        logd(TAG, "onActivityResult(): req=%s", requestCode);
+        switch (requestCode) {
+            case REQUEST_CODE_SET_DEFAULT:
+                onDefaultServiceSet(resultCode);
+                break;
+        }
+    }
+
+    private void onDefaultServiceSet(int resultCode) {
+        logd(TAG, "resultCode=%d", resultCode);
+        switch (resultCode) {
+            case RESULT_OK:
+                logd("Autofill service set.");
+                Snackbar.make(findViewById(R.id.settings_layout),
+                        R.string.settings_autofill_service_set, Snackbar.LENGTH_SHORT)
+                        .show();
+                break;
+            case RESULT_CANCELED:
+                logd("Autofill service not selected.");
+                Snackbar.make(findViewById(R.id.settings_layout),
+                        R.string.settings_autofill_service_not_set, Snackbar.LENGTH_SHORT)
+                        .show();
+                break;
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/simple/BasicHeuristicsService.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/simple/BasicHeuristicsService.java
new file mode 100644
index 0000000..843440c
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/simple/BasicHeuristicsService.java
@@ -0,0 +1,105 @@
+/*
+ * 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.example.android.autofill.service.simple;
+
+import android.app.assist.AssistStructure.ViewNode;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+
+import com.example.android.autofill.service.MyAutofillService;
+
+/**
+ * A basic service that uses some rudimentary heuristics to identify fields that are not explicitly
+ * marked with autofill hints.
+ *
+ * <p>The goal of this class is to provide a simple autofill service implementation that is easy
+ * to understand and extend, but it should <strong>not</strong> be used as-is on real apps because
+ * it lacks fundamental security requirements such as data partitioning and package verification
+ * &mdashthese requirements are fullfilled by {@link MyAutofillService}. *
+ */
+public class BasicHeuristicsService extends BasicService {
+
+    private static final String TAG = "BasicHeuristicsService";
+
+    @Override
+    @Nullable
+    protected String getHint(@NonNull ViewNode node) {
+
+        // First try the explicit autofill hints...
+
+        String hint = super.getHint(node);
+        if (hint != null) return hint;
+
+        // Then try some rudimentary heuristics based on other node properties
+
+        String viewHint = node.getHint();
+        hint = inferHint(viewHint);
+        if (hint != null) {
+            Log.d(TAG, "Found hint using view hint(" + viewHint + "): " + hint);
+            return hint;
+        } else if (!TextUtils.isEmpty(viewHint)) {
+            Log.v(TAG, "No hint using view hint: " + viewHint);
+        }
+
+        String resourceId = node.getIdEntry();
+        hint = inferHint(resourceId);
+        if (hint != null) {
+            Log.d(TAG, "Found hint using resourceId(" + resourceId + "): " + hint);
+            return hint;
+        } else if (!TextUtils.isEmpty(resourceId)) {
+            Log.v(TAG, "No hint using resourceId: " + resourceId);
+        }
+
+        CharSequence text = node.getText();
+        CharSequence className = node.getClassName();
+        if (text != null && className != null && className.toString().contains("EditText")) {
+            hint = inferHint(text.toString());
+            if (hint != null) {
+                // NODE: text should not be logged, as it could contain PII
+                Log.d(TAG, "Found hint using text(" + text + "): " + hint);
+                return hint;
+            }
+        } else if (!TextUtils.isEmpty(text)) {
+            // NODE: text should not be logged, as it could contain PII
+            Log.v(TAG, "No hint using text: " + text + " and class " + className);
+        }
+        return null;
+    }
+
+    /**
+     * Uses heuristics to infer an autofill hint from a {@code string}.
+     *
+     * @return standard autofill hint, or {@code null} when it could not be inferred.
+     */
+    @Nullable
+    protected String inferHint(@Nullable String string) {
+        if (string == null) return null;
+
+        string = string.toLowerCase();
+        if (string.contains("password")) return View.AUTOFILL_HINT_PASSWORD;
+        if (string.contains("username")
+                || (string.contains("login") && string.contains("id")))
+            return View.AUTOFILL_HINT_USERNAME;
+        if (string.contains("email")) return View.AUTOFILL_HINT_EMAIL_ADDRESS;
+        if (string.contains("name")) return View.AUTOFILL_HINT_NAME;
+        if (string.contains("phone")) return View.AUTOFILL_HINT_PHONE;
+
+        return null;
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/simple/BasicService.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/simple/BasicService.java
new file mode 100644
index 0000000..92d6436
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/simple/BasicService.java
@@ -0,0 +1,213 @@
+/*
+ * 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.example.android.autofill.service.simple;
+
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
+import android.os.CancellationSignal;
+import android.service.autofill.AutofillService;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillCallback;
+import android.service.autofill.FillContext;
+import android.service.autofill.FillRequest;
+import android.service.autofill.FillResponse;
+import android.service.autofill.SaveCallback;
+import android.service.autofill.SaveInfo;
+import android.service.autofill.SaveRequest;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.util.Log;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+
+import com.example.android.autofill.service.MyAutofillService;
+import com.example.android.autofill.service.R;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * A very basic {@link AutofillService} implementation that only shows dynamic-generated datasets
+ * and don't persist the saved data.
+ *
+ * <p>The goal of this class is to provide a simple autofill service implementation that is easy
+ * to understand and extend, but it should <strong>not</strong> be used as-is on real apps because
+ * it lacks fundamental security requirements such as data partitioning and package verification
+ * &mdashthese requirements are fullfilled by {@link MyAutofillService}.
+ */
+public class BasicService extends AutofillService {
+
+    private static final String TAG = "BasicService";
+
+    /**
+     * Number of datasets sent on each request - we're simple, that value is hardcoded in our DNA!
+     */
+    private static final int NUMBER_DATASETS = 4;
+
+    @Override
+    public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
+            FillCallback callback) {
+        Log.d(TAG, "onFillRequest()");
+
+        // Find autofillable fields
+        AssistStructure structure = getLatestAssistStructure(request);
+        Map<String, AutofillId> fields = getAutofillableFields(structure);
+        Log.d(TAG, "autofillable fields:" + fields);
+
+        if (fields.isEmpty()) {
+            toast("No autofill hints found");
+            callback.onSuccess(null);
+            return;
+        }
+
+        // Create the base response
+        FillResponse.Builder response = new FillResponse.Builder();
+
+        // 1.Add the dynamic datasets
+        String packageName = getApplicationContext().getPackageName();
+        for (int i = 1; i <= NUMBER_DATASETS; i++) {
+            Dataset.Builder dataset = new Dataset.Builder();
+            for (Entry<String, AutofillId> field : fields.entrySet()) {
+                String hint = field.getKey();
+                AutofillId id = field.getValue();
+                String value = hint + i;
+                // We're simple - our dataset values are hardcoded as "hintN" (for example,
+                // "username1", "username2") and they're displayed as such, except if they're a
+                // password
+                String displayValue = hint.contains("password") ? "password for #" + i : value;
+                RemoteViews presentation = newDatasetPresentation(packageName, displayValue);
+                dataset.setValue(id, AutofillValue.forText(value), presentation);
+            }
+            response.addDataset(dataset.build());
+        }
+
+        // 2.Add save info
+        Collection<AutofillId> ids = fields.values();
+        AutofillId[] requiredIds = new AutofillId[ids.size()];
+        ids.toArray(requiredIds);
+        response.setSaveInfo(
+                // We're simple, so we're generic
+                new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC, requiredIds).build());
+
+        // 3.Profit!
+        callback.onSuccess(response.build());
+    }
+
+    @Override
+    public void onSaveRequest(SaveRequest request, SaveCallback callback) {
+        Log.d(TAG, "onSaveRequest()");
+        toast("Save not supported");
+        callback.onSuccess();
+    }
+
+    /**
+     * Parses the {@link AssistStructure} representing the activity being autofilled, and returns a
+     * map of autofillable fields (represented by their autofill ids) mapped by the hint associate
+     * with them.
+     *
+     * <p>An autofillable field is a {@link ViewNode} whose {@link #getHint(ViewNode)} metho
+     */
+    @NonNull
+    private Map<String, AutofillId> getAutofillableFields(@NonNull AssistStructure structure) {
+        Map<String, AutofillId> fields = new ArrayMap<>();
+        int nodes = structure.getWindowNodeCount();
+        for (int i = 0; i < nodes; i++) {
+            ViewNode node = structure.getWindowNodeAt(i).getRootViewNode();
+            addAutofillableFields(fields, node);
+        }
+        return fields;
+    }
+
+    /**
+     * Adds any autofillable view from the {@link ViewNode} and its descendants to the map.
+     */
+    private void addAutofillableFields(@NonNull Map<String, AutofillId> fields,
+            @NonNull ViewNode node) {
+        int type = node.getAutofillType();
+        // We're simple, we just autofill text fields.
+        if (type == View.AUTOFILL_TYPE_TEXT) {
+            String hint = getHint(node);
+            if (hint != null) {
+                AutofillId id = node.getAutofillId();
+                if (!fields.containsKey(hint)) {
+                    Log.v(TAG, "Setting hint " + hint + " on " + id);
+                    fields.put(hint, id);
+                } else {
+                    Log.v(TAG, "Ignoring hint " + hint + " on " + id
+                            + " because it was already set");
+                }
+            }
+        }
+        int childrenSize = node.getChildCount();
+        for (int i = 0; i < childrenSize; i++) {
+            addAutofillableFields(fields, node.getChildAt(i));
+        }
+    }
+
+    /**
+     * Gets the autofill hint associated with the given node.
+     *
+     * <p>By default it just return the first entry on the node's
+     * {@link ViewNode#getAutofillHints() autofillHints} (when available), but subclasses could
+     * extend it to use heuristics when the app developer didn't explicitly provide these hints.
+     *
+     */
+    @Nullable
+    protected String getHint(@NonNull ViewNode node) {
+        String[] hints = node.getAutofillHints();
+        if (hints == null) return null;
+
+        // We're simple, we only care about the first hint
+        String hint = hints[0].toLowerCase();
+        return hint;
+    }
+
+    /**
+     * Helper method to get the {@link AssistStructure} associated with the latest request
+     * in an autofill context.
+     */
+    @NonNull
+    private static AssistStructure getLatestAssistStructure(@NonNull FillRequest request) {
+        List<FillContext> fillContexts = request.getFillContexts();
+        return fillContexts.get(fillContexts.size() - 1).getStructure();
+    }
+
+    /**
+     * Helper method to create a dataset presentation with the given text.
+     */
+    @NonNull
+    private static RemoteViews newDatasetPresentation(@NonNull String packageName,
+            @NonNull CharSequence text) {
+        RemoteViews presentation =
+                new RemoteViews(packageName, R.layout.multidataset_service_list_item);
+        presentation.setTextViewText(R.id.text, text);
+        presentation.setImageViewResource(R.id.icon, R.mipmap.ic_launcher);
+        return presentation;
+    }
+
+    /**
+     * Displays a toast with the given message.
+     */
+    private void toast(@NonNull CharSequence message) {
+        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/AppExecutors.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/AppExecutors.java
new file mode 100644
index 0000000..9befaeb
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/AppExecutors.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.example.android.autofill.service.util;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+/**
+ * Global executor pools for the whole application.
+ * <p>
+ * Grouping tasks like this avoids the effects of task starvation (e.g. disk reads don't wait behind
+ * webservice requests).
+ */
+public class AppExecutors {
+
+    private static final int THREAD_COUNT = 3;
+
+    private final Executor diskIO;
+
+    private final Executor networkIO;
+
+    private final Executor mainThread;
+
+    @VisibleForTesting
+    AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) {
+        this.diskIO = diskIO;
+        this.networkIO = networkIO;
+        this.mainThread = mainThread;
+    }
+
+    public AppExecutors() {
+        this(new DiskIOThreadExecutor(), Executors.newFixedThreadPool(THREAD_COUNT),
+                new MainThreadExecutor());
+    }
+
+    public Executor diskIO() {
+        return diskIO;
+    }
+
+    public Executor networkIO() {
+        return networkIO;
+    }
+
+    public Executor mainThread() {
+        return mainThread;
+    }
+
+    private static class MainThreadExecutor implements Executor {
+        private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
+
+        @Override
+        public void execute(@NonNull Runnable command) {
+            mainThreadHandler.post(command);
+        }
+    }
+
+    /**
+     * Executor that runs a task on a new background thread.
+     */
+    private static class DiskIOThreadExecutor implements Executor {
+
+        private final Executor mDiskIO;
+
+        public DiskIOThreadExecutor() {
+            mDiskIO = Executors.newSingleThreadExecutor();
+        }
+
+        @Override
+        public void execute(@NonNull Runnable command) {
+            mDiskIO.execute(command);
+        }
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/SecurityHelper.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/SecurityHelper.java
new file mode 100644
index 0000000..5311a5f
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/SecurityHelper.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.example.android.autofill.service.util;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+/**
+ * Helper class for security checks.
+ */
+public final class SecurityHelper {
+
+    private SecurityHelper() {
+        throw new UnsupportedOperationException("Provides static methods only.");
+    }
+
+    /**
+     * Gets the fingerprint of the signed certificate of a package.
+     */
+    public static String getFingerprint(PackageInfo packageInfo, String packageName) throws
+            PackageManager.NameNotFoundException, IOException, NoSuchAlgorithmException,
+            CertificateException {
+        Signature[] signatures = packageInfo.signatures;
+        if (signatures.length != 1) {
+            throw new SecurityException(packageName + " has " + signatures.length + " signatures");
+        }
+        byte[] cert = signatures[0].toByteArray();
+        try (InputStream input = new ByteArrayInputStream(cert)) {
+            CertificateFactory factory = CertificateFactory.getInstance("X509");
+            X509Certificate x509 = (X509Certificate) factory.generateCertificate(input);
+            MessageDigest md = MessageDigest.getInstance("SHA256");
+            byte[] publicKey = md.digest(x509.getEncoded());
+            return toHexFormat(publicKey);
+        }
+    }
+
+    private static String toHexFormat(byte[] bytes) {
+        StringBuilder builder = new StringBuilder(bytes.length * 2);
+        for (int i = 0; i < bytes.length; i++) {
+            String hex = Integer.toHexString(bytes[i]);
+            int length = hex.length();
+            if (length == 1) {
+                hex = "0" + hex;
+            }
+            if (length > 2) {
+                hex = hex.substring(length - 2, length);
+            }
+            builder.append(hex.toUpperCase());
+            if (i < (bytes.length - 1)) {
+                builder.append(':');
+            }
+        }
+        return builder.toString();
+    }
+}
diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/Util.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/Util.java
new file mode 100644
index 0000000..a86deea
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/Util.java
@@ -0,0 +1,312 @@
+/*
+ * 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 com.example.android.autofill.service.util;
+
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
+import android.app.assist.AssistStructure.WindowNode;
+import android.os.Bundle;
+import android.service.autofill.FillContext;
+import android.service.autofill.SaveInfo;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewStructure.HtmlInfo;
+import android.view.autofill.AutofillValue;
+
+import com.google.common.base.Joiner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public final class Util {
+
+    public static final String EXTRA_DATASET_NAME = "dataset_name";
+    public static final String EXTRA_FOR_RESPONSE = "for_response";
+    public static final NodeFilter AUTOFILL_ID_FILTER = (node, id) ->
+            id.equals(node.getAutofillId());
+    private static final String TAG = "AutofillSample";
+    public static LogLevel sLoggingLevel = LogLevel.Off;
+
+    private static void bundleToString(StringBuilder builder, Bundle data) {
+        final Set<String> keySet = data.keySet();
+        builder.append("[Bundle with ").append(keySet.size()).append(" keys:");
+        for (String key : keySet) {
+            builder.append(' ').append(key).append('=');
+            Object value = data.get(key);
+            if ((value instanceof Bundle)) {
+                bundleToString(builder, (Bundle) value);
+            } else {
+                builder.append((value instanceof Object[])
+                        ? Arrays.toString((Object[]) value) : value);
+            }
+        }
+        builder.append(']');
+    }
+
+    public static String bundleToString(Bundle data) {
+        if (data == null) {
+            return "N/A";
+        }
+        final StringBuilder builder = new StringBuilder();
+        bundleToString(builder, data);
+        return builder.toString();
+    }
+
+    public static String getTypeAsString(int type) {
+        switch (type) {
+            case View.AUTOFILL_TYPE_TEXT:
+                return "TYPE_TEXT";
+            case View.AUTOFILL_TYPE_LIST:
+                return "TYPE_LIST";
+            case View.AUTOFILL_TYPE_NONE:
+                return "TYPE_NONE";
+            case View.AUTOFILL_TYPE_TOGGLE:
+                return "TYPE_TOGGLE";
+            case View.AUTOFILL_TYPE_DATE:
+                return "TYPE_DATE";
+        }
+        return "UNKNOWN_TYPE";
+    }
+
+    private static String getAutofillValueAndTypeAsString(AutofillValue value) {
+        if (value == null) return "null";
+
+        StringBuilder builder = new StringBuilder(value.toString()).append('(');
+        if (value.isText()) {
+            builder.append("isText");
+        } else if (value.isDate()) {
+            builder.append("isDate");
+        } else if (value.isToggle()) {
+            builder.append("isToggle");
+        } else if (value.isList()) {
+            builder.append("isList");
+        }
+        return builder.append(')').toString();
+    }
+
+    public static void dumpStructure(AssistStructure structure) {
+        if (logVerboseEnabled()) {
+            int nodeCount = structure.getWindowNodeCount();
+            logv("dumpStructure(): component=%s numberNodes=%d",
+                    structure.getActivityComponent(), nodeCount);
+            for (int i = 0; i < nodeCount; i++) {
+                logv("node #%d", i);
+                WindowNode node = structure.getWindowNodeAt(i);
+                dumpNode(new StringBuilder(), "  ", node.getRootViewNode(), 0);
+            }
+        }
+    }
+
+    private static void dumpNode(StringBuilder builder, String prefix, ViewNode node, int childNumber) {
+        builder.append(prefix)
+                .append("child #").append(childNumber).append("\n");
+
+        builder.append(prefix)
+                .append("autoFillId: ").append(node.getAutofillId())
+                .append("\tidEntry: ").append(node.getIdEntry())
+                .append("\tid: ").append(node.getId())
+                .append("\tclassName: ").append(node.getClassName())
+                .append('\n');
+
+        builder.append(prefix)
+                .append("focused: ").append(node.isFocused())
+                .append("\tvisibility").append(node.getVisibility())
+                .append("\tchecked: ").append(node.isChecked())
+                .append("\twebDomain: ").append(node.getWebDomain())
+                .append("\thint: ").append(node.getHint())
+                .append('\n');
+
+        HtmlInfo htmlInfo = node.getHtmlInfo();
+
+        if (htmlInfo != null) {
+            builder.append(prefix)
+                    .append("HTML TAG: ").append(htmlInfo.getTag())
+                    .append(" attrs: ").append(htmlInfo.getAttributes())
+                    .append('\n');
+        }
+
+        String[] afHints = node.getAutofillHints();
+        CharSequence[] options = node.getAutofillOptions();
+        builder.append(prefix).append("afType: ").append(getTypeAsString(node.getAutofillType()))
+                .append("\tafValue:")
+                .append(getAutofillValueAndTypeAsString(node.getAutofillValue()))
+                .append("\tafOptions:").append(options == null ? "N/A" : Arrays.toString(options))
+                .append("\tafHints: ").append(afHints == null ? "N/A" : Arrays.toString(afHints))
+                .append("\tinputType:").append(node.getInputType())
+                .append('\n');
+
+        int numberChildren = node.getChildCount();
+        builder.append(prefix).append("# children: ").append(numberChildren)
+                .append("\ttext: ").append(node.getText())
+                .append('\n');
+
+        final String prefix2 = prefix + "  ";
+        for (int i = 0; i < numberChildren; i++) {
+            dumpNode(builder, prefix2, node.getChildAt(i), i);
+        }
+        logv(builder.toString());
+    }
+
+    public static String getSaveTypeAsString(int type) {
+        List<String> types = new ArrayList<>();
+        if ((type & SaveInfo.SAVE_DATA_TYPE_ADDRESS) != 0) {
+            types.add("ADDRESS");
+        }
+        if ((type & SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD) != 0) {
+            types.add("CREDIT_CARD");
+        }
+        if ((type & SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS) != 0) {
+            types.add("EMAIL_ADDRESS");
+        }
+        if ((type & SaveInfo.SAVE_DATA_TYPE_USERNAME) != 0) {
+            types.add("USERNAME");
+        }
+        if ((type & SaveInfo.SAVE_DATA_TYPE_PASSWORD) != 0) {
+            types.add("PASSWORD");
+        }
+        if (types.isEmpty()) {
+            return "UNKNOWN(" + type + ")";
+        }
+        return Joiner.on('|').join(types);
+    }
+
+    /**
+     * Gets a node if it matches the filter criteria for the given id.
+     */
+    public static ViewNode findNodeByFilter(@NonNull List<FillContext> contexts, @NonNull Object id,
+            @NonNull NodeFilter filter) {
+        for (FillContext context : contexts) {
+            ViewNode node = findNodeByFilter(context.getStructure(), id, filter);
+            if (node != null) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets a node if it matches the filter criteria for the given id.
+     */
+    public static ViewNode findNodeByFilter(@NonNull AssistStructure structure, @NonNull Object id,
+            @NonNull NodeFilter filter) {
+        logv("Parsing request for activity %s", structure.getActivityComponent());
+        final int nodes = structure.getWindowNodeCount();
+        for (int i = 0; i < nodes; i++) {
+            final WindowNode windowNode = structure.getWindowNodeAt(i);
+            final ViewNode rootNode = windowNode.getRootViewNode();
+            final ViewNode node = findNodeByFilter(rootNode, id, filter);
+            if (node != null) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets a node if it matches the filter criteria for the given id.
+     */
+    public static ViewNode findNodeByFilter(@NonNull ViewNode node, @NonNull Object id,
+            @NonNull NodeFilter filter) {
+        if (filter.matches(node, id)) {
+            return node;
+        }
+        final int childrenSize = node.getChildCount();
+        if (childrenSize > 0) {
+            for (int i = 0; i < childrenSize; i++) {
+                final ViewNode found = findNodeByFilter(node.getChildAt(i), id, filter);
+                if (found != null) {
+                    return found;
+                }
+            }
+        }
+        return null;
+    }
+
+    public static void logd(String message, Object... params) {
+        if (logDebugEnabled()) {
+            Log.d(TAG, String.format(message, params));
+        }
+    }
+
+    public static void logv(String message, Object... params) {
+        if (logVerboseEnabled()) {
+            Log.v(TAG, String.format(message, params));
+        }
+    }
+
+    public static boolean logDebugEnabled() {
+        return sLoggingLevel.ordinal() >= LogLevel.Debug.ordinal();
+    }
+
+    public static boolean logVerboseEnabled() {
+        return sLoggingLevel.ordinal() >= LogLevel.Verbose.ordinal();
+    }
+
+    public static void logw(String message, Object... params) {
+        Log.w(TAG, String.format(message, params));
+    }
+
+    public static void logw(Throwable throwable, String message, Object... params) {
+        Log.w(TAG, String.format(message, params), throwable);
+    }
+
+    public static void loge(String message, Object... params) {
+        Log.e(TAG, String.format(message, params));
+    }
+
+    public static void loge(Throwable throwable, String message, Object... params) {
+        Log.e(TAG, String.format(message, params), throwable);
+    }
+
+    public static void setLoggingLevel(LogLevel level) {
+        sLoggingLevel = level;
+    }
+
+    /**
+     * Helper method for getting the index of a CharSequence object in an array.
+     */
+    public static int indexOf(@NonNull CharSequence[] array, CharSequence charSequence) {
+        int index = -1;
+        if (charSequence == null) {
+            return index;
+        }
+        for (int i = 0; i < array.length; i++) {
+            if (charSequence.equals(array[i])) {
+                index = i;
+                break;
+            }
+        }
+        return index;
+    }
+
+    public enum LogLevel {Off, Debug, Verbose}
+
+    public enum DalCheckRequirement {Disabled, LoginOnly, AllUrls}
+
+    /**
+     * Helper interface used to filter Assist nodes.
+     */
+    public interface NodeFilter {
+        /**
+         * Returns whether the node passes the filter for such given id.
+         */
+        boolean matches(ViewNode node, Object id);
+    }
+}
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_add_black_24dp.xml b/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_add_black_24dp.xml
new file mode 100644
index 0000000..ed8512a
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_add_black_24dp.xml
@@ -0,0 +1,24 @@
+<!--
+ * 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
+</vector>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_delete_forever_black_24dp.xml b/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_delete_forever_black_24dp.xml
new file mode 100644
index 0000000..5b5927d
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_delete_forever_black_24dp.xml
@@ -0,0 +1,25 @@
+<!--
+ * 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:alpha="0.50"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z" />
+</vector>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_lock_black_24dp.xml b/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_lock_black_24dp.xml
new file mode 100644
index 0000000..6e18f1a
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_lock_black_24dp.xml
@@ -0,0 +1,24 @@
+<!--
+ * 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" />
+</vector>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_person_black_24dp.xml b/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_person_black_24dp.xml
new file mode 100644
index 0000000..032db12
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/drawable-v24/ic_person_black_24dp.xml
@@ -0,0 +1,25 @@
+<!--
+ * 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:alpha="0.50"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
+</vector>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/drawable/list_divider.xml b/input/autofill/AutofillFramework/afservice/src/main/res/drawable/list_divider.xml
new file mode 100644
index 0000000..3d6d162
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/drawable/list_divider.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (c) 2017 Google Inc.
+  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.apache.org/licenses/LICENSE-2.0
+  Unless required by applicable law or agreed to in writing, software distributed under the License
+  is distributed on an "AS IS" BASIS, WITHOUT 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="rectangle">
+    <size android:height="1dp" android:width="1dp" />
+    <solid android:color="@color/light_grey" />
+</shape>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/activity_field_picker.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/activity_field_picker.xml
new file mode 100644
index 0000000..949dbfb
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/activity_field_picker.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+<android.support.constraint.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"
+    android:layout_margin="@dimen/activity_vertical_margin">
+
+    <TextView
+        android:id="@+id/listTitle"
+        style="@style/Manual.Header"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        tools:text="@string/manual_data_picker_title"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/fieldsList"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:background="@null"
+        android:elevation="@dimen/card_elevation"
+        android:listDivider="@drawable/list_divider"
+        android:orientation="vertical"
+        android:scrollbarStyle="insideOverlay"
+        android:scrollbars="vertical"
+        app:layoutManager="LinearLayoutManager"
+        app:layout_behavior="@string/appbar_scrolling_view_behavior"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        tools:listitem="@layout/dataset_field" />
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/dataset_field.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/dataset_field.xml
new file mode 100644
index 0000000..b441dba
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/dataset_field.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="@dimen/spacing_large"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <TextView
+        style="@style/Manual.Content"
+        android:id="@+id/fieldType"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/manual_dataset_name_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="Username" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/dataset_suggestion.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/dataset_suggestion.xml
new file mode 100644
index 0000000..030de0a
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/dataset_suggestion.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toBottomOf="@+id/fieldTypes"
+        android:src="@drawable/ic_person_black_24dp"/>
+
+    <TextView
+        style="@style/Manual.Header"
+        android:id="@+id/datasetNameLabel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/manual_dataset_name_label"
+        app:layout_constraintStart_toEndOf="@+id/icon"
+        app:layout_constraintTop_toTopOf="parent" />
+    <TextView
+        style="@style/Manual.Content"
+        android:id="@+id/datasetName"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintStart_toStartOf="@+id/datasetNameLabel"
+        app:layout_constraintTop_toBottomOf="@+id/datasetNameLabel"
+        tools:text="dataset-1"/>
+    <TextView
+        style="@style/Manual.Header"
+        android:id="@+id/fieldTypesLabel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/manual_field_types_label"
+        app:layout_constraintStart_toStartOf="@+id/datasetName"
+        app:layout_constraintTop_toBottomOf="@+id/datasetName"/>
+    <TextView
+        style="@style/Manual.Content"
+        android:id="@+id/fieldTypes"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintStart_toStartOf="@+id/fieldTypesLabel"
+        app:layout_constraintTop_toBottomOf="@+id/fieldTypesLabel"
+        tools:text="Username, password, and more."/>
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_auth_activity.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_auth_activity.xml
new file mode 100644
index 0000000..844ea0a
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_auth_activity.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<android.support.constraint.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/authLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:importantForAutofill="noExcludeDescendants"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context="com.example.android.autofill.service.AuthActivity">
+
+    <TextView
+        android:id="@+id/master_login_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:text="@string/autofill_master_login_label"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/password_label"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/master_password"
+        android:text="@string/auth_password_label"
+        app:layout_constraintEnd_toStartOf="@+id/master_password"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/master_login_header" />
+
+    <EditText
+        android:id="@+id/master_password"
+        android:layout_width="@dimen/text_field_width"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:inputType="textPassword"
+        app:layout_constraintBottom_toBottomOf="@+id/password_label"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/password_label"
+        app:layout_constraintTop_toTopOf="@+id/password_label" />
+
+    <TextView
+        android:id="@+id/cancel"
+        style="@style/Widget.AppCompat.Button.Borderless"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:text="@string/auth_cancel"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toStartOf="@+id/login"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/master_password" />
+
+    <TextView
+        android:id="@+id/login"
+        style="@style/Widget.AppCompat.Button.Borderless"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:text="@string/auth_login_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/cancel"
+        app:layout_constraintTop_toTopOf="@+id/cancel" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_list_item.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_list_item.xml
new file mode 100644
index 0000000..442d54e
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_list_item.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/white"
+    android:orientation="horizontal">
+
+    <TextView
+        android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:minHeight="?android:attr/listPreferredItemHeightSmall"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+        android:textAppearance="?android:attr/textAppearanceListItemSmall" />
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:src="@drawable/ic_person_black_24dp" />
+</LinearLayout>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_manual_activity.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_manual_activity.xml
new file mode 100644
index 0000000..56117aa
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_manual_activity.xml
@@ -0,0 +1,39 @@
+<?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.
+-->
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_margin="@dimen/activity_vertical_margin"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/suggestionsList"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:background="@null"
+        android:elevation="@dimen/card_elevation"
+        android:listDivider="@drawable/list_divider"
+        android:orientation="vertical"
+        android:scrollbarStyle="insideOverlay"
+        android:scrollbars="vertical"
+        app:layoutManager="LinearLayoutManager"
+        app:layout_behavior="@string/appbar_scrolling_view_behavior"
+        tools:listitem="@layout/dataset_suggestion" />
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_activity.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_activity.xml
new file mode 100644
index 0000000..ce77e27
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_activity.xml
@@ -0,0 +1,267 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:importantForAutofill="no"
+    android:scrollbarStyle="insideOverlay"
+    android:scrollbars="vertical">
+
+    <LinearLayout
+        android:id="@+id/settings_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:paddingBottom="@dimen/spacing_large">
+
+        <TextView
+            style="@style/Settings.Header"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/settings_authentication_header" />
+
+        <LinearLayout
+            android:id="@+id/settings_auth_responses_container"
+            style="@style/Settings.Container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:id="@+id/settings_auth_responses_label"
+                style="@style/Settings.Label"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/settings_authenticate_responses" />
+
+            <Switch
+                android:id="@+id/settings_auth_responses_switch"
+                style="@style/Settings.Switch"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/padding_normal"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/settings_auth_datasets_container"
+            style="@style/Settings.Container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:id="@+id/settings_auth_datasets_label"
+                style="@style/Settings.Label"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/settings_authenticate_datasets" />
+
+            <Switch
+                android:id="@+id/settings_auth_datasets_switch"
+                style="@style/Settings.Switch"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/padding_normal"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/settings_auth_credentials_container"
+            style="@style/Settings.Container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:id="@+id/settings_auth_credentials_label"
+                style="@style/Settings.Label"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/settings_auth_credentials_label" />
+
+            <ImageView
+                android:id="@+id/settings_auth_credentials_icon"
+                style="@style/Settings.Switch"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/padding_normal"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:src="@drawable/ic_person_black_24dp" />
+        </LinearLayout>
+
+        <TextView
+            style="@style/Settings.Header"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/settings_data_header" />
+
+        <LinearLayout
+            android:id="@+id/settings_add_data_container"
+            style="@style/Settings.Container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:id="@+id/settings_add_data_label"
+                style="@style/Settings.Label"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/settings_add_data_label" />
+
+            <ImageView
+                android:id="@+id/settings_add_data_icon"
+                style="@style/Settings.Switch"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/padding_normal"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:src="@drawable/ic_add_black_24dp" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/settings_clear_data_container"
+            style="@style/Settings.Container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:id="@+id/settings_clear_data_label"
+                style="@style/Settings.Label"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/settings_clear_data_label" />
+
+            <ImageView
+                android:id="@+id/settings_clear_data_icon"
+                style="@style/Settings.Switch"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/padding_normal"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:src="@drawable/ic_delete_forever_black_24dp" />
+        </LinearLayout>
+
+        <TextView
+            style="@style/Settings.Header"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/settings_dal_header" />
+
+        <RadioGroup
+            android:id="@+id/dalCheckRequirementContainer"
+            style="@style/Settings.Container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <RadioButton
+                android:id="@+id/dalDisabled"
+                style="@style/Settings.Label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:text="@string/settings_dal_disabled" />
+
+            <RadioButton
+                android:id="@+id/dalLoginOnly"
+                style="@style/Settings.Label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:text="@string/settings_dal_login_only" />
+
+            <RadioButton
+                android:id="@+id/dalAllUrls"
+                style="@style/Settings.Label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:text="@string/settings_dal_all_urls" />
+        </RadioGroup>
+
+        <TextView
+            style="@style/Settings.Header"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/settings_logging_header" />
+
+        <RadioGroup
+            android:id="@+id/loggingLevelContainer"
+            style="@style/Settings.Container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <RadioButton
+                android:id="@+id/loggingOff"
+                style="@style/Settings.Label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:text="@string/settings_logging_off" />
+
+            <RadioButton
+                android:id="@+id/loggingDebug"
+                style="@style/Settings.Label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:text="@string/settings_logging_debug" />
+
+            <RadioButton
+                android:id="@+id/loggingVerbose"
+                style="@style/Settings.Label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:text="@string/settings_logging_verbose" />
+        </RadioGroup>
+
+        <TextView
+            style="@style/Settings.Header"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/settings_enable_header" />
+
+        <LinearLayout
+            android:id="@+id/settingsSetServiceContainer"
+            style="@style/Settings.Container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:id="@+id/settingsSetServiceLabel"
+                style="@style/Settings.Label"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/settings_set_service" />
+
+            <Switch
+                android:id="@+id/settingsSetServiceSwitch"
+                style="@style/Settings.Switch"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/padding_normal"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen" />
+        </LinearLayout>
+    </LinearLayout>
+</android.support.v4.widget.NestedScrollView>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml
new file mode 100644
index 0000000..530451e
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<NumberPicker xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/number_of_datasets_picker"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginStart="@dimen/padding_normal"
+    android:minHeight="@dimen/a11y_min_touch_target_dimen" />
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml
new file mode 100644
index 0000000..a84e45f
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<EditText xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/master_password_field"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_margin="@dimen/spacing_normal"
+    android:importantForAutofill="no"
+    android:padding="@dimen/spacing_normal">
+
+    <requestFocus />
+</EditText>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-hdpi/ic_launcher.png b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100755
index 0000000..93465c0
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-mdpi/ic_launcher.png b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100755
index 0000000..6d5c2bb
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-xhdpi/ic_launcher.png b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..72ecd6c
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-xxhdpi/ic_launcher.png b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..698fd4c
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100755
index 0000000..b64a676
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/raw/default_field_types b/input/autofill/AutofillFramework/afservice/src/main/res/raw/default_field_types
new file mode 100644
index 0000000..637edea
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/raw/default_field_types
@@ -0,0 +1,1165 @@
+[
+  {
+    "autofillHints": [
+      "country"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "countryseed"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "country"
+    }
+  },
+  {
+    "autofillHints": [
+      "transaction-amount"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "seed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "transaction-amount"
+    }
+  },
+  {
+    "autofillHints": [
+      "cc-family-name"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "familynameseed"
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "cc-family-name"
+    }
+  },
+  {
+    "autofillHints": [
+      "postal-code",
+      "postalCode"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "1000seed"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "postalCode"
+    }
+  },
+  {
+    "autofillHints": [
+      "language"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [
+          "Bulgarian",
+          "Croatian",
+          "Czech",
+          "Danish",
+          "Dutch",
+          "English",
+          "Estonian"
+        ]
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "language"
+    }
+  },
+  {
+    "autofillHints": [
+      "tel-national"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "tel-nationalseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "tel-national"
+    }
+  },
+  {
+    "autofillHints": [
+      "transaction-currency"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [
+          "USD",
+          "CAD",
+          "KYD",
+          "CRC"
+        ]
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "transaction-currency"
+    }
+  },
+  {
+    "autofillHints": [
+      "billing"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "billingseed"
+      },
+      "partition": 1,
+      "saveInfo": 0,
+      "typeName": "billing"
+    }
+  },
+  {
+    "autofillHints": [
+      "emailAddress",
+      "email"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "emailAddressseed"
+      },
+      "partition": 2,
+      "saveInfo": 16,
+      "typeName": "emailAddress"
+    }
+  },
+  {
+    "autofillHints": [
+      "password",
+      "current-password"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "usernameseed"
+      },
+      "partition": 0,
+      "saveInfo": 1,
+      "typeName": "password"
+    }
+  },
+  {
+    "autofillHints": [
+      "honorific-suffix"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [
+          "san",
+          "kun",
+          "chan",
+          "sama"
+        ]
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "honorific-suffix"
+    }
+  },
+  {
+    "autofillHints": [
+      "shipping"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "shippingseed"
+      },
+      "partition": 1,
+      "saveInfo": 0,
+      "typeName": "shipping"
+    }
+  },
+  {
+    "autofillHints": [
+      "pager"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "pagerseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "pager"
+    }
+  },
+  {
+    "autofillHints": [
+      "impp"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "imppseed"
+      },
+      "partition": 2,
+      "saveInfo": 16,
+      "typeName": "impp"
+    }
+  },
+  {
+    "autofillHints": [
+      "bday-month"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "dateTemplate": "curr_time",
+        "strictExampleSet": [
+          "1",
+          "2",
+          "3",
+          "4",
+          "5",
+          "6",
+          "7",
+          "8",
+          "9",
+          "10",
+          "11",
+          "12"
+        ],
+        "textTemplate": "bday-monthseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "bday-month"
+    }
+  },
+  {
+    "autofillHints": [
+      "tel-local-prefix"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "tel-local-prefixseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "tel-local-prefix"
+    }
+  },
+  {
+    "autofillHints": [
+      "tel"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "telseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "tel"
+    }
+  },
+  {
+    "autofillHints": [
+      "fax"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "faxseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "fax"
+    }
+  },
+  {
+    "autofillHints": [
+      "honorific-prefix"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [
+          "Miss",
+          "Ms.",
+          "Mr.",
+          "Mx.",
+          "Sr.",
+          "Dr.",
+          "Lady",
+          "Lord"
+        ]
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "honorific-prefix"
+    }
+  },
+  {
+    "autofillHints": [
+      "bday-year"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "dateTemplate": "curr_time",
+        "strictExampleSet": []
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "bday-year"
+    }
+  },
+  {
+    "autofillHints": [
+      "creditCardExpirationMonth",
+      "cc-exp-month"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3,
+        4
+      ],
+      "fakeData": {
+        "dateTemplate": "curr_time",
+        "strictExampleSet": [
+          "1",
+          "2",
+          "3",
+          "4",
+          "5",
+          "6",
+          "7",
+          "8",
+          "9",
+          "10",
+          "11",
+          "12"
+        ]
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "creditCardExpirationMonth"
+    }
+  },
+  {
+    "autofillHints": [
+      "work"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "workseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "work"
+    }
+  },
+  {
+    "autofillHints": [
+      "cc-csc",
+      "creditCardSecurityCode"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "seedseedseed"
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "creditCardSecurityCode"
+    }
+  },
+  {
+    "autofillHints": [
+      "cc-type"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "cc-typeseed"
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "cc-type"
+    }
+  },
+  {
+    "autofillHints": [
+      "bday-day"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "dateTemplate": "curr_time",
+        "strictExampleSet": [],
+        "textTemplate": "seed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "bday-day"
+    }
+  },
+  {
+    "autofillHints": [
+      "address-line2"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "Bldg. seed"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "address-line2"
+    }
+  },
+  {
+    "autofillHints": [
+      "address-line1"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "seed Fake Ln."
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "address-line1"
+    }
+  },
+  {
+    "autofillHints": [
+      "postalAddress"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "seed Fake Ln, Fake, FA, FAA 10001"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "postalAddress"
+    }
+  },
+  {
+    "autofillHints": [
+      "address-line3"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "Suite seed"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "address-line3"
+    }
+  },
+  {
+    "autofillHints": [
+      "phone"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "seed2345678910"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "phone"
+    }
+  },
+  {
+    "autofillHints": [
+      "tel_extension"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "tel_extensionseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "tel_extension"
+    }
+  },
+  {
+    "autofillHints": [
+      "creditCardNumber",
+      "cc-number"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "seed234567"
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "creditCardNumber"
+    }
+  },
+  {
+    "autofillHints": [
+      "name"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "nameseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "name"
+    }
+  },
+  {
+    "autofillHints": [
+      "additional-name"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "additional-nameseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "additional-name"
+    }
+  },
+  {
+    "autofillHints": [
+      "tel-local"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "tel-localseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "tel-local"
+    }
+  },
+  {
+    "autofillHints": [
+      "bday"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        4
+      ],
+      "fakeData": {
+        "dateTemplate": "curr_time",
+        "strictExampleSet": []
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "bday"
+    }
+  },
+  {
+    "autofillHints": [
+      "street-address"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "street-addressseed"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "street-address"
+    }
+  },
+  {
+    "autofillHints": [
+      "cc-given-name"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "cc-given-nameseed"
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "cc-given-name"
+    }
+  },
+  {
+    "autofillHints": [
+      "creditCardExpirationDate",
+      "cc-exp"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        4
+      ],
+      "fakeData": {
+        "dateTemplate": "curr_time",
+        "strictExampleSet": []
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "creditCardExpirationDate"
+    }
+  },
+  {
+    "autofillHints": [
+      "creditCardExpirationYear",
+      "cc-exp-year"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3,
+        4
+      ],
+      "fakeData": {
+        "dateTemplate": "curr_time",
+        "strictExampleSet": [],
+        "textTemplate": "creditCardExpirationYearseed"
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "creditCardExpirationYear"
+    }
+  },
+  {
+    "autofillHints": [
+      "organization-title"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "organization-titleseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "organization-title"
+    }
+  },
+  {
+    "autofillHints": [
+      "sex"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [
+          "Male",
+          "Female",
+          "Other"
+        ]
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "sex"
+    }
+  },
+  {
+    "autofillHints": [
+      "section-"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "section-seed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "section-"
+    }
+  },
+  {
+    "autofillHints": [
+      "country-name"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [
+          "USA",
+          "Mexico",
+          "Canada"
+        ]
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "country-name"
+    }
+  },
+  {
+    "autofillHints": [
+      "photo"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "photoseed.jpg"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "photo"
+    }
+  },
+  {
+    "autofillHints": [
+      "tel-area-code"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "tel-area-codeseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "tel-area-code"
+    }
+  },
+  {
+    "autofillHints": [
+      "new-password"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "new-passwordseed"
+      },
+      "partition": 0,
+      "saveInfo": 1,
+      "typeName": "new-password"
+    }
+  },
+  {
+    "autofillHints": [
+      "tel-local-suffix"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "tel-local-suffixseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "tel-local-suffix"
+    }
+  },
+  {
+    "autofillHints": [
+      "family-name"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "family-nameseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "family-name"
+    }
+  },
+  {
+    "autofillHints": [
+      "url"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "https://www.google.com/?count\u003dseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "url"
+    }
+  },
+  {
+    "autofillHints": [
+      "home"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "homeseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "home"
+    }
+  },
+  {
+    "autofillHints": [
+      "address-level4"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "address-level4seed"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "address-level4"
+    }
+  },
+  {
+    "autofillHints": [
+      "address-level3"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "address-level3seed"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "address-level3"
+    }
+  },
+  {
+    "autofillHints": [
+      "organization"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "organizationseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "organization"
+    }
+  },
+  {
+    "autofillHints": [
+      "cc-additional-name"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "cc-additional-nameseed"
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "cc-additional-name"
+    }
+  },
+  {
+    "autofillHints": [
+      "address-level2"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "address-level2seed"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "address-level2"
+    }
+  },
+  {
+    "autofillHints": [
+      "given-name"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "given-nameseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "given-name"
+    }
+  },
+  {
+    "autofillHints": [
+      "address-level1"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "address-level1seed"
+      },
+      "partition": 1,
+      "saveInfo": 2,
+      "typeName": "address-level1"
+    }
+  },
+  {
+    "autofillHints": [
+      "creditCardExpirationDay"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3,
+        4
+      ],
+      "fakeData": {
+        "dateTemplate": "curr_time",
+        "strictExampleSet": [],
+        "textTemplate": "creditCardExpirationDayseed"
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "creditCardExpirationDay"
+    }
+  },
+  {
+    "autofillHints": [
+      "cc-name"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "Firstnameseed Lastnameseed"
+      },
+      "partition": 3,
+      "saveInfo": 4,
+      "typeName": "cc-name"
+    }
+  },
+  {
+    "autofillHints": [
+      "username"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "usernameseed"
+      },
+      "partition": 0,
+      "saveInfo": 8,
+      "typeName": "username"
+    }
+  },
+  {
+    "autofillHints": [
+      "tel-country-code"
+    ],
+    "fieldType": {
+      "autofillTypes": [
+        1,
+        3
+      ],
+      "fakeData": {
+        "strictExampleSet": [],
+        "textTemplate": "tel-country-codeseed"
+      },
+      "partition": 0,
+      "saveInfo": 0,
+      "typeName": "tel-country-code"
+    }
+  }
+]
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/values/colors.xml b/input/autofill/AutofillFramework/afservice/src/main/res/values/colors.xml
new file mode 100644
index 0000000..4d80b9f
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/values/colors.xml
@@ -0,0 +1,21 @@
+<?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>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+    <color name="light_grey">#ffeeeeee</color>
+</resources>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/values/dimens.xml b/input/autofill/AutofillFramework/afservice/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..8a21b70
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/values/dimens.xml
@@ -0,0 +1,25 @@
+<?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>
+    <dimen name="padding_normal">16dp</dimen>
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="spacing_normal">8dp</dimen>
+    <dimen name="spacing_large">32dp</dimen>
+    <dimen name="a11y_min_touch_target_dimen">48dp</dimen>
+    <dimen name="text_field_width">250sp</dimen>
+    <dimen name="card_elevation">2dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/values/strings.xml b/input/autofill/AutofillFramework/afservice/src/main/res/values/strings.xml
new file mode 100644
index 0000000..e7b1f88
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/values/strings.xml
@@ -0,0 +1,117 @@
+<!--
+ * 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>
+    <string name="invalid_package_signature">Invalid package signature</string>
+    <string name="security_exception">Web domain security exception.</string>
+    <string name="dal_exception">DAL verification failure.</string>
+    <string name="autofill_sign_in_prompt">Tap to sign in.</string>
+    <string name="autofill_manual_prompt">Tap to manually select data.</string>
+    <string name="authentication_name">Autofill Authentication</string>
+    <string name="manual_name">Manual (Auto)fill</string>
+    <string name="manual_field_picker_name">Select Field</string>
+    <string name="settings_name">Autofill Settings</string>
+    <string name="settings_cancel">Cancel</string>
+    <string name="settings_save">Save</string>
+    <string name="settings_authenticate_responses">Authenticate Responses</string>
+    <string name="settings_authenticate_datasets">Authenticate Datasets</string>
+    <string name="settings_add_data_label">Add fake Autofill data</string>
+    <string name="settings_add_data_title">Add Autofill Datasets</string>
+    <string name="settings_select_number_of_datasets">Select number of Datasets.</string>
+    <plurals name="settings_add_data_success">
+        <item quantity="one">Added %d Dataset.</item>
+        <item quantity="other">Added %d Datasets.</item>
+    </plurals>
+    <string name="settings_clear_data_label">Clear all autofill data (including credentials)</string>
+    <string name="settings_clear_data_confirmation">Are you sure you want to delete all autofill
+        data from the sample service?
+    </string>
+    <string name="settings_clear_data_confirmation_title">Confirmation</string>
+    <string name="settings_authentication_header">Authentication</string>
+    <string name="settings_data_header">Data</string>
+    <string name="settings_logging_header">Logging</string>
+    <string name="settings_logging_off">Off</string>
+    <string name="settings_logging_debug">Debug</string>
+    <string name="settings_logging_verbose">Verbose</string>
+
+    <string name="settings_dal_header">DAL Check Requirement</string>
+    <string name="settings_dal_disabled">Disabled</string>
+    <string name="settings_dal_login_only">Login Credentials Only</string>
+    <string name="settings_dal_all_urls">Handle All URLs</string>
+
+    <string name="settings_enable_header">Enable/Disable</string>
+    <string name="settings_set_service">Set default Autofill service</string>
+    <string name="settings_disable_service">Disable Autofill services</string>
+    <string name="settings_autofill_disabled_message">Autofill service has been disabled.</string>
+    <string name="settings_autofill_service_set">Sample service set to default.</string>
+    <string name="settings_autofill_service_not_set">Sample service not set to default.</string>
+    <string name="settings_auth_credentials_label">Update credentials</string>
+    <string name="settings_auth_enter_current_password">Enter current password</string>
+    <string name="settings_auth_enter_new_password">Enter new password</string>
+    <string name="settings_auth_change_credentials_title">Change credentials</string>
+    <string name="settings_number_of_datasets_label">Number of Datasets</string>
+    <string name="autofill_master_login_label">Autofill Master Login</string>
+    <string name="auth_password_label">Password</string>
+    <string name="auth_cancel">Cancel</string>
+    <string name="auth_login_label">Login</string>
+    <string name="settings_ok">OK</string>
+    <string name="manual_dataset_name_label">Dataset Name</string>
+    <string name="manual_field_types_label">Field Types</string>
+    <string name="manual_data_picker_title">Fields for %1$s</string>
+    <string-array name="month_array">
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+        <item>4</item>
+        <item>5</item>
+        <item>6</item>
+        <item>7</item>
+        <item>8</item>
+        <item>9</item>
+        <item>10</item>
+        <item>11</item>
+        <item>12</item>
+    </string-array>
+
+    <string-array name="day_array">
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+        <item>4</item>
+        <item>5</item>
+        <item>6</item>
+        <item>7</item>
+        <item>8</item>
+        <item>9</item>
+        <item>10</item>
+        <item>11</item>
+        <item>12</item>
+        <item>13</item>
+        <item>14</item>
+        <item>15</item>
+        <item>16</item>
+        <item>17</item>
+        <item>18</item>
+        <item>19</item>
+        <item>20</item>
+        <item>21</item>
+        <item>22</item>
+        <item>23</item>
+        <item>24</item>
+        <item>25</item>
+        <item>26</item>
+        <item>27</item>
+    </string-array>
+</resources>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/values/styles.xml b/input/autofill/AutofillFramework/afservice/src/main/res/values/styles.xml
new file mode 100644
index 0000000..a7e7bf2
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/values/styles.xml
@@ -0,0 +1,67 @@
+<!--
+ * 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>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+    <style name="Settings.Label" parent="@style/TextAppearance.AppCompat.Body1">
+        <item name="android:ellipsize">end</item>
+        <item name="android:lines">1</item>
+        <item name="android:paddingBottom">@dimen/spacing_normal</item>
+        <item name="android:paddingTop">@dimen/spacing_normal</item>
+    </style>
+
+    <style name="Settings.Container" parent="">
+        <item name="android:background">?android:selectableItemBackground</item>
+        <item name="android:gravity">center_vertical</item>
+        <item name="android:minHeight">?android:listPreferredItemHeightSmall</item>
+        <item name="android:orientation">horizontal</item>
+        <item name="android:paddingEnd">?android:listPreferredItemPaddingEnd</item>
+        <item name="android:paddingStart">?android:listPreferredItemPaddingStart</item>
+    </style>
+
+    <style name="Settings.Switch" parent="">
+        <!-- We make the parent view clickable instead for better touch feedback -->
+        <item name="android:background">@null</item>
+        <item name="android:clickable">false</item>
+    </style>
+
+    <style name="Settings.Header" parent="@style/TextAppearance.AppCompat.Large">
+        <item name="android:paddingStart">?android:listPreferredItemPaddingStart</item>
+        <item name="android:paddingBottom">@dimen/spacing_normal</item>
+        <item name="android:paddingTop">@dimen/spacing_large</item>
+    </style>
+
+    <style name="Manual.Header" parent="@style/TextAppearance.AppCompat.Large">
+        <item name="android:paddingStart">?android:listPreferredItemPaddingStart</item>
+        <item name="android:paddingEnd">?android:listPreferredItemPaddingEnd</item>
+        <item name="android:paddingBottom">@dimen/spacing_normal</item>
+        <item name="android:paddingTop">@dimen/spacing_normal</item>
+    </style>
+
+    <style name="Manual.Content" parent="@style/TextAppearance.AppCompat.Medium">
+        <item name="android:paddingStart">?android:listPreferredItemPaddingStart</item>
+        <item name="android:paddingEnd">?android:listPreferredItemPaddingEnd</item>
+        <item name="android:paddingBottom">@dimen/spacing_normal</item>
+        <item name="android:paddingTop">@dimen/spacing_normal</item>
+    </style>
+</resources>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/xml/multidataset_service.xml b/input/autofill/AutofillFramework/afservice/src/main/res/xml/multidataset_service.xml
new file mode 100644
index 0000000..de58167
--- /dev/null
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/xml/multidataset_service.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<!--
+Attributes for the AutoFill service that tell the framework what will act as the Autofill service's
+Settings Activity. This is pointed to in the service's meta-data in the application's manifest.
+-->
+<autofill-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:settingsActivity="com.example.android.autofill.service.settings.SettingsActivity" />
\ No newline at end of file
diff --git a/input/autofill/AutofillFramework/build.gradle b/input/autofill/AutofillFramework/build.gradle
index efb29d9..5e6d6a3 100644
--- a/input/autofill/AutofillFramework/build.gradle
+++ b/input/autofill/AutofillFramework/build.gradle
@@ -1,32 +1,29 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 buildscript {
-  repositories {
-    jcenter()
-    maven {
-      url 'https://maven.google.com'
+    repositories {
+        jcenter()
+        google()
     }
-  }
-  dependencies {
-    classpath 'com.android.tools.build:gradle:2.3.3'
-  }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+    }
 }
 
 allprojects {
-  repositories {
-    jcenter()
-    maven {
-      url 'https://maven.google.com'
+    repositories {
+        jcenter()
+        google()
     }
-  }
 }
 
 // BEGIN_EXCLUDE
 import com.example.android.samples.build.SampleGenPlugin
+
 apply plugin: SampleGenPlugin
 
 samplegen {
-  pathToBuild "../../../../../build"
-  pathToSamplesCommon "../../../common"
+    pathToBuild "../../../../../build"
+    pathToSamplesCommon "../../../common"
 }
 apply from: "../../../../../build/build.gradle"
 // END_EXCLUDE
diff --git a/input/autofill/AutofillFramework/gradle/wrapper/gradle-wrapper.jar b/input/autofill/AutofillFramework/gradle/wrapper/gradle-wrapper.jar
index 8c0fb64..13372ae 100644
--- a/input/autofill/AutofillFramework/gradle/wrapper/gradle-wrapper.jar
+++ b/input/autofill/AutofillFramework/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/input/autofill/AutofillFramework/gradle/wrapper/gradle-wrapper.properties b/input/autofill/AutofillFramework/gradle/wrapper/gradle-wrapper.properties
index 6342626..f176f79 100644
--- a/input/autofill/AutofillFramework/gradle/wrapper/gradle-wrapper.properties
+++ b/input/autofill/AutofillFramework/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Jul 28 14:29:44 PDT 2017
+#Fri Jan 12 11:03:13 PST 2018
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/input/autofill/AutofillFramework/gradlew b/input/autofill/AutofillFramework/gradlew
index 91a7e26..9d82f78 100755
--- a/input/autofill/AutofillFramework/gradlew
+++ b/input/autofill/AutofillFramework/gradlew
@@ -42,11 +42,6 @@
     ;;
 esac
 
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
-    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
 # Attempt to set APP_HOME
 # Resolve links: $0 may be a link
 PRG="$0"
@@ -61,9 +56,9 @@
     fi
 done
 SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
+cd "`dirname \"$PRG\"`/" >/dev/null
 APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
+cd "$SAVED" >/dev/null
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
@@ -114,6 +109,7 @@
 if $cygwin ; then
     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
 
     # We build the pattern for arguments to be converted via cygpath
     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml
index 2470645..88a0d72 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -75,7 +75,7 @@
         <service
             android:name=".multidatasetservice.MyAutofillService"
             android:label="Multi-Dataset Autofill Service"
-            android:permission="android.permission.BIND_AUTOFILL">
+            android:permission="android.permission.BIND_AUTOFILL_SERVICE" >
             <meta-data
                 android:name="android.autofill"
                 android:resource="@xml/multidataset_service" />
@@ -88,4 +88,4 @@
         <activity android:name=".multidatasetservice.AuthActivity" />
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/input/autofill/AutofillFramework/kotlinApp/README.md b/input/autofill/AutofillFramework/kotlinApp/README.md
index 282a1ea..d0ab0e0 100644
--- a/input/autofill/AutofillFramework/kotlinApp/README.md
+++ b/input/autofill/AutofillFramework/kotlinApp/README.md
@@ -1,11 +1,17 @@
+Warning: This sample is currently outdated and you should reference the Java version instead.
+============================================================================================
 
-Android AutofillFramework Sample
-===================================
+Android AutofillFramework Sample (Kotlin)
+=========================================
 
 This sample demonstrates the use of the Autofill Framework. It includes implementations of client
 Activities with views that should be autofilled, and a Service that can provide autofill data to
 client Activities.
 
+Maintainer's Note
+------------------
+**IMPORTANT:** The Kotlin version of this sample is temporarily out of date. Until this is corrected, you should reference the Java version instead.
+
 Introduction
 ------------
 
diff --git a/input/autofill/AutofillFramework/kotlinApp/build.gradle b/input/autofill/AutofillFramework/kotlinApp/build.gradle
index 6fc4282..7eb0ddd 100644
--- a/input/autofill/AutofillFramework/kotlinApp/build.gradle
+++ b/input/autofill/AutofillFramework/kotlinApp/build.gradle
@@ -7,7 +7,7 @@
     }
     ext.kotlin_version = '1.1.4-3'
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
diff --git a/input/autofill/AutofillFramework/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/input/autofill/AutofillFramework/kotlinApp/gradle/wrapper/gradle-wrapper.properties
index cb80c87..34facd6 100644
--- a/input/autofill/AutofillFramework/kotlinApp/gradle/wrapper/gradle-wrapper.properties
+++ b/input/autofill/AutofillFramework/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/input/autofill/AutofillFramework/settings.gradle b/input/autofill/AutofillFramework/settings.gradle
index 9464a35..2d0eb20 100644
--- a/input/autofill/AutofillFramework/settings.gradle
+++ b/input/autofill/AutofillFramework/settings.gradle
@@ -1 +1,2 @@
+include ':afservice'
 include 'Application'
diff --git a/input/autofill/AutofillFramework/template-params.xml b/input/autofill/AutofillFramework/template-params.xml
index b355587..37d6bd2 100644
--- a/input/autofill/AutofillFramework/template-params.xml
+++ b/input/autofill/AutofillFramework/template-params.xml
@@ -19,7 +19,7 @@
     <name>AutofillFramework</name>
     <group>Input</group>  <!-- This field will be deprecated in the future
                             and replaced with the "categories" tags below. -->
-    <package>com.example.android.autofillframework</package>
+    <package>com.example.android.autofill.app</package>
 
     <!-- change minSdk if needed-->
     <minSdk>26</minSdk>
diff --git a/input/gestures/BasicGestureDetect/gradle/wrapper/gradle-wrapper.properties b/input/gestures/BasicGestureDetect/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/input/gestures/BasicGestureDetect/gradle/wrapper/gradle-wrapper.properties
+++ b/input/gestures/BasicGestureDetect/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/input/keyboard/CommitContentSampleApp/build.gradle b/input/keyboard/CommitContentSampleApp/build.gradle
index 1e30651..144d85e 100644
--- a/input/keyboard/CommitContentSampleApp/build.gradle
+++ b/input/keyboard/CommitContentSampleApp/build.gradle
@@ -5,7 +5,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
diff --git a/input/keyboard/CommitContentSampleApp/gradle/wrapper/gradle-wrapper.properties b/input/keyboard/CommitContentSampleApp/gradle/wrapper/gradle-wrapper.properties
index d9028cc..fc5d442 100644
--- a/input/keyboard/CommitContentSampleApp/gradle/wrapper/gradle-wrapper.properties
+++ b/input/keyboard/CommitContentSampleApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/input/keyboard/CommitContentSampleIME/build.gradle b/input/keyboard/CommitContentSampleIME/build.gradle
index 1e30651..144d85e 100644
--- a/input/keyboard/CommitContentSampleIME/build.gradle
+++ b/input/keyboard/CommitContentSampleIME/build.gradle
@@ -5,7 +5,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
diff --git a/input/keyboard/CommitContentSampleIME/gradle/wrapper/gradle-wrapper.properties b/input/keyboard/CommitContentSampleIME/gradle/wrapper/gradle-wrapper.properties
index d9028cc..fc5d442 100644
--- a/input/keyboard/CommitContentSampleIME/gradle/wrapper/gradle-wrapper.properties
+++ b/input/keyboard/CommitContentSampleIME/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/input/multitouch/BasicMultitouch/gradle/wrapper/gradle-wrapper.properties b/input/multitouch/BasicMultitouch/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/input/multitouch/BasicMultitouch/gradle/wrapper/gradle-wrapper.properties
+++ b/input/multitouch/BasicMultitouch/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/BasicMediaDecoder/gradle/wrapper/gradle-wrapper.properties b/media/BasicMediaDecoder/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/media/BasicMediaDecoder/gradle/wrapper/gradle-wrapper.properties
+++ b/media/BasicMediaDecoder/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/BasicMediaRouter/gradle/wrapper/gradle-wrapper.properties b/media/BasicMediaRouter/gradle/wrapper/gradle-wrapper.properties
index 7ec3018..21e2aff 100644
--- a/media/BasicMediaRouter/gradle/wrapper/gradle-wrapper.properties
+++ b/media/BasicMediaRouter/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/Camera2Basic/gradle/wrapper/gradle-wrapper.properties b/media/Camera2Basic/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/media/Camera2Basic/gradle/wrapper/gradle-wrapper.properties
+++ b/media/Camera2Basic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/Camera2Basic/kotlinApp/.google/packaging.yaml b/media/Camera2Basic/kotlinApp/.google/packaging.yaml
new file mode 100644
index 0000000..9382485
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/.google/packaging.yaml
@@ -0,0 +1,23 @@
+
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [Media, Camera, Camera2]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-Camera2Basic
+level:        INTERMEDIATE
+icon:         screenshots/icon-web.png
+apiRefs:
+    - android:android.hardware.camera2.CameraManager
+    - android:android.hardware.camera2.CameraDevice
+    - android:android.hardware.camera2.CameraCharacteristics
+    - android:android.hardware.camera2.CameraCaptureSession
+    - android:android.hardware.camera2.CaptureRequest
+    - android:android.hardware.camera2.CaptureResult
+    - android:android.view.TextureView
+license: apache2
diff --git a/system/RuntimePermissionsBasic/Application/.gitignore b/media/Camera2Basic/kotlinApp/Application/.gitignore
similarity index 100%
rename from system/RuntimePermissionsBasic/Application/.gitignore
rename to media/Camera2Basic/kotlinApp/Application/.gitignore
diff --git a/media/Camera2Basic/kotlinApp/Application/build.gradle b/media/Camera2Basic/kotlinApp/Application/build.gradle
new file mode 100644
index 0000000..c30a09a
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/build.gradle
@@ -0,0 +1,28 @@
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion 26
+    buildToolsVersion '26.0.2'
+    defaultConfig {
+        applicationId "com.example.android.camera2basic"
+        minSdkVersion 21
+        targetSdkVersion 26
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:26.1.0"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+}
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/AndroidManifest.xml b/media/Camera2Basic/kotlinApp/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5b0b5b0
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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.example.android.camera2basic">
+
+    <uses-permission android:name="android.permission.CAMERA" />
+
+    <uses-feature android:name="android.hardware.camera" />
+    <uses-feature android:name="android.hardware.camera.autofocus" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/MaterialTheme">
+
+        <activity android:name=".CameraActivity"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ActivityExtensions.kt b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ActivityExtensions.kt
new file mode 100644
index 0000000..14dcfa7
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ActivityExtensions.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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 com.example.android.camera2basic
+
+import android.support.v4.app.FragmentActivity
+import android.support.v4.content.ContextCompat
+import android.widget.Toast
+
+/**
+ * This file illustrates Kotlin's Extension Functions by extending FragmentActivity.
+ */
+
+/**
+ * Shows a [Toast] on the UI thread.
+ *
+ * @param text The message to show
+ */
+fun FragmentActivity.showToast(text: String) {
+    runOnUiThread { Toast.makeText(this, text, Toast.LENGTH_SHORT).show() }
+}
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/AutoFitTextureView.kt b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/AutoFitTextureView.kt
new file mode 100644
index 0000000..8214557
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/AutoFitTextureView.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 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 com.example.android.camera2basic
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.TextureView
+import android.view.View
+
+/**
+ * A [TextureView] that can be adjusted to a specified aspect ratio.
+ */
+class AutoFitTextureView @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyle: Int = 0
+) : TextureView(context, attrs, defStyle) {
+
+    private var ratioWidth = 0
+    private var ratioHeight = 0
+
+    /**
+     * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
+     * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
+     * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
+     *
+     * @param width  Relative horizontal size
+     * @param height Relative vertical size
+     */
+    fun setAspectRatio(width: Int, height: Int) {
+        if (width < 0 || height < 0) {
+            throw IllegalArgumentException("Size cannot be negative.")
+        }
+        ratioWidth = width
+        ratioHeight = height
+        requestLayout()
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        val width = View.MeasureSpec.getSize(widthMeasureSpec)
+        val height = View.MeasureSpec.getSize(heightMeasureSpec)
+        if (ratioWidth == 0 || ratioHeight == 0) {
+            setMeasuredDimension(width, height)
+        } else {
+            if (width < height * ratioWidth / ratioHeight) {
+                setMeasuredDimension(width, width * ratioHeight / ratioWidth)
+            } else {
+                setMeasuredDimension(height * ratioWidth / ratioHeight, height)
+            }
+        }
+    }
+
+}
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.kt b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.kt
new file mode 100644
index 0000000..c55df1b
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.kt
@@ -0,0 +1,817 @@
+/*
+ * Copyright 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 com.example.android.camera2basic
+
+import android.Manifest
+import android.app.AlertDialog
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.res.Configuration
+import android.graphics.ImageFormat
+import android.graphics.Matrix
+import android.graphics.Point
+import android.graphics.RectF
+import android.graphics.SurfaceTexture
+import android.hardware.camera2.CameraAccessException
+import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraManager
+import android.hardware.camera2.CameraMetadata
+import android.hardware.camera2.CaptureRequest
+import android.hardware.camera2.CaptureResult
+import android.hardware.camera2.TotalCaptureResult
+import android.media.ImageReader
+import android.os.Bundle
+import android.os.Handler
+import android.os.HandlerThread
+import android.support.v4.app.ActivityCompat
+import android.support.v4.app.Fragment
+import android.support.v4.content.ContextCompat
+import android.util.Log
+import android.util.Size
+import android.util.SparseIntArray
+import android.view.LayoutInflater
+import android.view.Surface
+import android.view.TextureView
+import android.view.View
+import android.view.ViewGroup
+import java.io.File
+import java.util.Arrays
+import java.util.Collections
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
+import kotlin.collections.ArrayList
+
+class Camera2BasicFragment : Fragment(), View.OnClickListener,
+        ActivityCompat.OnRequestPermissionsResultCallback {
+
+    /**
+     * [TextureView.SurfaceTextureListener] handles several lifecycle events on a
+     * [TextureView].
+     */
+    private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
+
+        override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) {
+            openCamera(width, height)
+        }
+
+        override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {
+            configureTransform(width, height)
+        }
+
+        override fun onSurfaceTextureDestroyed(texture: SurfaceTexture) = true
+
+        override fun onSurfaceTextureUpdated(texture: SurfaceTexture) = Unit
+
+    }
+
+    /**
+     * ID of the current [CameraDevice].
+     */
+    private lateinit var cameraId: String
+
+    /**
+     * An [AutoFitTextureView] for camera preview.
+     */
+    private lateinit var textureView: AutoFitTextureView
+
+    /**
+     * A [CameraCaptureSession] for camera preview.
+     */
+    private var captureSession: CameraCaptureSession? = null
+
+    /**
+     * A reference to the opened [CameraDevice].
+     */
+    private var cameraDevice: CameraDevice? = null
+
+    /**
+     * The [android.util.Size] of camera preview.
+     */
+    private lateinit var previewSize: Size
+
+    /**
+     * [CameraDevice.StateCallback] is called when [CameraDevice] changes its state.
+     */
+    private val stateCallback = object : CameraDevice.StateCallback() {
+
+        override fun onOpened(cameraDevice: CameraDevice) {
+            cameraOpenCloseLock.release()
+            this@Camera2BasicFragment.cameraDevice = cameraDevice
+            createCameraPreviewSession()
+        }
+
+        override fun onDisconnected(cameraDevice: CameraDevice) {
+            cameraOpenCloseLock.release()
+            cameraDevice.close()
+            this@Camera2BasicFragment.cameraDevice = null
+        }
+
+        override fun onError(cameraDevice: CameraDevice, error: Int) {
+            onDisconnected(cameraDevice)
+            this@Camera2BasicFragment.activity?.finish()
+        }
+
+    }
+
+    /**
+     * An additional thread for running tasks that shouldn't block the UI.
+     */
+    private var backgroundThread: HandlerThread? = null
+
+    /**
+     * A [Handler] for running tasks in the background.
+     */
+    private var backgroundHandler: Handler? = null
+
+    /**
+     * An [ImageReader] that handles still image capture.
+     */
+    private var imageReader: ImageReader? = null
+
+    /**
+     * This is the output file for our picture.
+     */
+    private lateinit var file: File
+
+    /**
+     * This a callback object for the [ImageReader]. "onImageAvailable" will be called when a
+     * still image is ready to be saved.
+     */
+    private val onImageAvailableListener = ImageReader.OnImageAvailableListener {
+        backgroundHandler?.post(ImageSaver(it.acquireNextImage(), file))
+    }
+
+    /**
+     * [CaptureRequest.Builder] for the camera preview
+     */
+    private lateinit var previewRequestBuilder: CaptureRequest.Builder
+
+    /**
+     * [CaptureRequest] generated by [.previewRequestBuilder]
+     */
+    private lateinit var previewRequest: CaptureRequest
+
+    /**
+     * The current state of camera state for taking pictures.
+     *
+     * @see .captureCallback
+     */
+    private var state = STATE_PREVIEW
+
+    /**
+     * A [Semaphore] to prevent the app from exiting before closing the camera.
+     */
+    private val cameraOpenCloseLock = Semaphore(1)
+
+    /**
+     * Whether the current camera device supports Flash or not.
+     */
+    private var flashSupported = false
+
+    /**
+     * Orientation of the camera sensor
+     */
+    private var sensorOrientation = 0
+
+    /**
+     * A [CameraCaptureSession.CaptureCallback] that handles events related to JPEG capture.
+     */
+    private val captureCallback = object : CameraCaptureSession.CaptureCallback() {
+
+        private fun process(result: CaptureResult) {
+            when (state) {
+                STATE_PREVIEW -> Unit // Do nothing when the camera preview is working normally.
+                STATE_WAITING_LOCK -> capturePicture(result)
+                STATE_WAITING_PRECAPTURE -> {
+                    // CONTROL_AE_STATE can be null on some devices
+                    val aeState = result.get(CaptureResult.CONTROL_AE_STATE)
+                    if (aeState == null ||
+                            aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
+                            aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
+                        state = STATE_WAITING_NON_PRECAPTURE
+                    }
+                }
+                STATE_WAITING_NON_PRECAPTURE -> {
+                    // CONTROL_AE_STATE can be null on some devices
+                    val aeState = result.get(CaptureResult.CONTROL_AE_STATE)
+                    if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
+                        state = STATE_PICTURE_TAKEN
+                        captureStillPicture()
+                    }
+                }
+            }
+        }
+
+        private fun capturePicture(result: CaptureResult) {
+            val afState = result.get(CaptureResult.CONTROL_AF_STATE)
+            if (afState == null) {
+                captureStillPicture()
+            } else if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED
+                    || afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
+                // CONTROL_AE_STATE can be null on some devices
+                val aeState = result.get(CaptureResult.CONTROL_AE_STATE)
+                if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
+                    state = STATE_PICTURE_TAKEN
+                    captureStillPicture()
+                } else {
+                    runPrecaptureSequence()
+                }
+            }
+        }
+
+        override fun onCaptureProgressed(session: CameraCaptureSession,
+                request: CaptureRequest,
+                partialResult: CaptureResult) {
+            process(partialResult)
+        }
+
+        override fun onCaptureCompleted(session: CameraCaptureSession,
+                request: CaptureRequest,
+                result: TotalCaptureResult) {
+            process(result)
+        }
+
+    }
+
+    override fun onCreateView(inflater: LayoutInflater,
+            container: ViewGroup?,
+            savedInstanceState: Bundle?
+    ): View? = inflater.inflate(R.layout.fragment_camera2_basic, container, false)
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        view.findViewById<View>(R.id.picture).setOnClickListener(this)
+        view.findViewById<View>(R.id.info).setOnClickListener(this)
+        textureView = view.findViewById(R.id.texture)
+    }
+
+    override fun onActivityCreated(savedInstanceState: Bundle?) {
+        super.onActivityCreated(savedInstanceState)
+        file = File(activity.getExternalFilesDir(null), PIC_FILE_NAME)
+    }
+
+    override fun onResume() {
+        super.onResume()
+        startBackgroundThread()
+
+        // When the screen is turned off and turned back on, the SurfaceTexture is already
+        // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
+        // a camera and start preview from here (otherwise, we wait until the surface is ready in
+        // the SurfaceTextureListener).
+        if (textureView.isAvailable) {
+            openCamera(textureView.width, textureView.height)
+        } else {
+            textureView.surfaceTextureListener = surfaceTextureListener
+        }
+    }
+
+    override fun onPause() {
+        closeCamera()
+        stopBackgroundThread()
+        super.onPause()
+    }
+
+    private fun requestCameraPermission() {
+        if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
+            ConfirmationDialog().show(childFragmentManager, FRAGMENT_DIALOG)
+        } else {
+            requestPermissions(arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION)
+        }
+    }
+
+    override fun onRequestPermissionsResult(requestCode: Int,
+            permissions: Array<String>,
+            grantResults: IntArray) {
+        if (requestCode == REQUEST_CAMERA_PERMISSION) {
+            if (grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
+                ErrorDialog.newInstance(getString(R.string.request_permission))
+                        .show(childFragmentManager, FRAGMENT_DIALOG)
+            }
+        } else {
+            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+        }
+    }
+
+    /**
+     * Sets up member variables related to camera.
+     *
+     * @param width  The width of available size for camera preview
+     * @param height The height of available size for camera preview
+     */
+    private fun setUpCameraOutputs(width: Int, height: Int) {
+        val manager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
+        try {
+            for (cameraId in manager.cameraIdList) {
+                val characteristics = manager.getCameraCharacteristics(cameraId)
+
+                // We don't use a front facing camera in this sample.
+                val cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING)
+                if (cameraDirection != null &&
+                        cameraDirection == CameraCharacteristics.LENS_FACING_FRONT) {
+                    continue
+                }
+
+                val map = characteristics.get(
+                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
+
+                // For still image captures, we use the largest available size.
+                val largest = Collections.max(
+                        Arrays.asList(*map.getOutputSizes(ImageFormat.JPEG)),
+                        CompareSizesByArea())
+                imageReader = ImageReader.newInstance(largest.width, largest.height,
+                        ImageFormat.JPEG, /*maxImages*/ 2).apply {
+                    setOnImageAvailableListener(onImageAvailableListener, backgroundHandler)
+                }
+
+                // Find out if we need to swap dimension to get the preview size relative to sensor
+                // coordinate.
+                val displayRotation = activity.windowManager.defaultDisplay.rotation
+
+                sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)
+                val swappedDimensions = areDimensionsSwapped(displayRotation)
+
+                val displaySize = Point()
+                activity.windowManager.defaultDisplay.getSize(displaySize)
+                val rotatedPreviewWidth = if (swappedDimensions) height else width
+                val rotatedPreviewHeight = if (swappedDimensions) width else height
+                var maxPreviewWidth = if (swappedDimensions) displaySize.y else displaySize.x
+                var maxPreviewHeight = if (swappedDimensions) displaySize.x else displaySize.y
+
+                if (maxPreviewWidth > MAX_PREVIEW_WIDTH) maxPreviewWidth = MAX_PREVIEW_WIDTH
+                if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) maxPreviewHeight = MAX_PREVIEW_HEIGHT
+
+                // Danger, W.R.! Attempting to use too large a preview size could  exceed the camera
+                // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
+                // garbage capture data.
+                previewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture::class.java),
+                        rotatedPreviewWidth, rotatedPreviewHeight,
+                        maxPreviewWidth, maxPreviewHeight,
+                        largest)
+
+                // We fit the aspect ratio of TextureView to the size of preview we picked.
+                if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+                    textureView.setAspectRatio(previewSize.width, previewSize.height)
+                } else {
+                    textureView.setAspectRatio(previewSize.height, previewSize.width)
+                }
+
+                // Check if the flash is supported.
+                flashSupported =
+                        characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) == true
+
+                this.cameraId = cameraId
+
+                // We've found a viable camera and finished setting up member variables,
+                // so we don't need to iterate through other available cameras.
+                return
+            }
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        } catch (e: NullPointerException) {
+            // Currently an NPE is thrown when the Camera2API is used but not supported on the
+            // device this code runs.
+            ErrorDialog.newInstance(getString(R.string.camera_error))
+                    .show(childFragmentManager, FRAGMENT_DIALOG)
+        }
+
+    }
+
+    /**
+     * Determines if the dimensions are swapped given the phone's current rotation.
+     *
+     * @param displayRotation The current rotation of the display
+     *
+     * @return true if the dimensions are swapped, false otherwise.
+     */
+    private fun areDimensionsSwapped(displayRotation: Int): Boolean {
+        var swappedDimensions = false
+        when (displayRotation) {
+            Surface.ROTATION_0, Surface.ROTATION_180 -> {
+                if (sensorOrientation == 90 || sensorOrientation == 270) {
+                    swappedDimensions = true
+                }
+            }
+            Surface.ROTATION_90, Surface.ROTATION_270 -> {
+                if (sensorOrientation == 0 || sensorOrientation == 180) {
+                    swappedDimensions = true
+                }
+            }
+            else -> {
+                Log.e(TAG, "Display rotation is invalid: $displayRotation")
+            }
+        }
+        return swappedDimensions
+    }
+
+    /**
+     * Opens the camera specified by [Camera2BasicFragment.cameraId].
+     */
+    private fun openCamera(width: Int, height: Int) {
+        val permission = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
+        if (permission != PackageManager.PERMISSION_GRANTED) {
+            requestCameraPermission()
+            return
+        }
+        setUpCameraOutputs(width, height)
+        configureTransform(width, height)
+        val manager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
+        try {
+            // Wait for camera to open - 2.5 seconds is sufficient
+            if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
+                throw RuntimeException("Time out waiting to lock camera opening.")
+            }
+            manager.openCamera(cameraId, stateCallback, backgroundHandler)
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        } catch (e: InterruptedException) {
+            throw RuntimeException("Interrupted while trying to lock camera opening.", e)
+        }
+
+    }
+
+    /**
+     * Closes the current [CameraDevice].
+     */
+    private fun closeCamera() {
+        try {
+            cameraOpenCloseLock.acquire()
+            captureSession?.close()
+            captureSession = null
+            cameraDevice?.close()
+            cameraDevice = null
+            imageReader?.close()
+            imageReader = null
+        } catch (e: InterruptedException) {
+            throw RuntimeException("Interrupted while trying to lock camera closing.", e)
+        } finally {
+            cameraOpenCloseLock.release()
+        }
+    }
+
+    /**
+     * Starts a background thread and its [Handler].
+     */
+    private fun startBackgroundThread() {
+        backgroundThread = HandlerThread("CameraBackground").also { it.start() }
+        backgroundHandler = Handler(backgroundThread?.looper)
+    }
+
+    /**
+     * Stops the background thread and its [Handler].
+     */
+    private fun stopBackgroundThread() {
+        backgroundThread?.quitSafely()
+        try {
+            backgroundThread?.join()
+            backgroundThread = null
+            backgroundHandler = null
+        } catch (e: InterruptedException) {
+            Log.e(TAG, e.toString())
+        }
+
+    }
+
+    /**
+     * Creates a new [CameraCaptureSession] for camera preview.
+     */
+    private fun createCameraPreviewSession() {
+        try {
+            val texture = textureView.surfaceTexture
+
+            // We configure the size of default buffer to be the size of camera preview we want.
+            texture.setDefaultBufferSize(previewSize.width, previewSize.height)
+
+            // This is the output Surface we need to start preview.
+            val surface = Surface(texture)
+
+            // We set up a CaptureRequest.Builder with the output Surface.
+            previewRequestBuilder = cameraDevice!!.createCaptureRequest(
+                    CameraDevice.TEMPLATE_PREVIEW
+            )
+            previewRequestBuilder.addTarget(surface)
+
+            // Here, we create a CameraCaptureSession for camera preview.
+            cameraDevice?.createCaptureSession(Arrays.asList(surface, imageReader?.surface),
+                    object : CameraCaptureSession.StateCallback() {
+
+                        override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
+                            // The camera is already closed
+                            if (cameraDevice == null) return
+
+                            // When the session is ready, we start displaying the preview.
+                            captureSession = cameraCaptureSession
+                            try {
+                                // Auto focus should be continuous for camera preview.
+                                previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
+                                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
+                                // Flash is automatically enabled when necessary.
+                                setAutoFlash(previewRequestBuilder)
+
+                                // Finally, we start displaying the camera preview.
+                                previewRequest = previewRequestBuilder.build()
+                                captureSession?.setRepeatingRequest(previewRequest,
+                                        captureCallback, backgroundHandler)
+                            } catch (e: CameraAccessException) {
+                                Log.e(TAG, e.toString())
+                            }
+
+                        }
+
+                        override fun onConfigureFailed(session: CameraCaptureSession) {
+                            activity.showToast("Failed")
+                        }
+                    }, null)
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        }
+
+    }
+
+    /**
+     * Configures the necessary [android.graphics.Matrix] transformation to `textureView`.
+     * This method should be called after the camera preview size is determined in
+     * setUpCameraOutputs and also the size of `textureView` is fixed.
+     *
+     * @param viewWidth  The width of `textureView`
+     * @param viewHeight The height of `textureView`
+     */
+    private fun configureTransform(viewWidth: Int, viewHeight: Int) {
+        activity ?: return
+        val rotation = activity.windowManager.defaultDisplay.rotation
+        val matrix = Matrix()
+        val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
+        val bufferRect = RectF(0f, 0f, previewSize.height.toFloat(), previewSize.width.toFloat())
+        val centerX = viewRect.centerX()
+        val centerY = viewRect.centerY()
+
+        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY())
+            val scale = Math.max(
+                    viewHeight.toFloat() / previewSize.height,
+                    viewWidth.toFloat() / previewSize.width)
+            with(matrix) {
+                setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL)
+                postScale(scale, scale, centerX, centerY)
+                postRotate((90 * (rotation - 2)).toFloat(), centerX, centerY)
+            }
+        } else if (Surface.ROTATION_180 == rotation) {
+            matrix.postRotate(180f, centerX, centerY)
+        }
+        textureView.setTransform(matrix)
+    }
+
+    /**
+     * Lock the focus as the first step for a still image capture.
+     */
+    private fun lockFocus() {
+        try {
+            // This is how to tell the camera to lock focus.
+            previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+                    CameraMetadata.CONTROL_AF_TRIGGER_START)
+            // Tell #captureCallback to wait for the lock.
+            state = STATE_WAITING_LOCK
+            captureSession?.capture(previewRequestBuilder.build(), captureCallback,
+                    backgroundHandler)
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        }
+
+    }
+
+    /**
+     * Run the precapture sequence for capturing a still image. This method should be called when
+     * we get a response in [.captureCallback] from [.lockFocus].
+     */
+    private fun runPrecaptureSequence() {
+        try {
+            // This is how to tell the camera to trigger.
+            previewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
+                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START)
+            // Tell #captureCallback to wait for the precapture sequence to be set.
+            state = STATE_WAITING_PRECAPTURE
+            captureSession?.capture(previewRequestBuilder.build(), captureCallback,
+                    backgroundHandler)
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        }
+
+    }
+
+    /**
+     * Capture a still picture. This method should be called when we get a response in
+     * [.captureCallback] from both [.lockFocus].
+     */
+    private fun captureStillPicture() {
+        try {
+            if (activity == null || cameraDevice == null) return
+            val rotation = activity.windowManager.defaultDisplay.rotation
+
+            // This is the CaptureRequest.Builder that we use to take a picture.
+            val captureBuilder = cameraDevice?.createCaptureRequest(
+                    CameraDevice.TEMPLATE_STILL_CAPTURE)?.apply {
+                addTarget(imageReader?.surface)
+
+                // Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X)
+                // We have to take that into account and rotate JPEG properly.
+                // For devices with orientation of 90, we return our mapping from ORIENTATIONS.
+                // For devices with orientation of 270, we need to rotate the JPEG 180 degrees.
+                set(CaptureRequest.JPEG_ORIENTATION,
+                        (ORIENTATIONS.get(rotation) + sensorOrientation + 270) % 360)
+
+                // Use the same AE and AF modes as the preview.
+                set(CaptureRequest.CONTROL_AF_MODE,
+                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
+            }?.also { setAutoFlash(it) }
+
+            val captureCallback = object : CameraCaptureSession.CaptureCallback() {
+
+                override fun onCaptureCompleted(session: CameraCaptureSession,
+                        request: CaptureRequest,
+                        result: TotalCaptureResult) {
+                    activity.showToast("Saved: $file")
+                    Log.d(TAG, file.toString())
+                    unlockFocus()
+                }
+            }
+
+            captureSession?.apply {
+                stopRepeating()
+                abortCaptures()
+                capture(captureBuilder?.build(), captureCallback, null)
+            }
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        }
+
+    }
+
+    /**
+     * Unlock the focus. This method should be called when still image capture sequence is
+     * finished.
+     */
+    private fun unlockFocus() {
+        try {
+            // Reset the auto-focus trigger
+            previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+                    CameraMetadata.CONTROL_AF_TRIGGER_CANCEL)
+            setAutoFlash(previewRequestBuilder)
+            captureSession?.capture(previewRequestBuilder.build(), captureCallback,
+                    backgroundHandler)
+            // After this, the camera will go back to the normal state of preview.
+            state = STATE_PREVIEW
+            captureSession?.setRepeatingRequest(previewRequest, captureCallback,
+                    backgroundHandler)
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        }
+
+    }
+
+    override fun onClick(view: View) {
+        when (view.id) {
+            R.id.picture -> lockFocus()
+            R.id.info -> {
+                if (activity != null) {
+                    AlertDialog.Builder(activity)
+                            .setMessage(R.string.intro_message)
+                            .setPositiveButton(android.R.string.ok, null)
+                            .show()
+                }
+            }
+        }
+    }
+
+    private fun setAutoFlash(requestBuilder: CaptureRequest.Builder) {
+        if (flashSupported) {
+            requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
+                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
+        }
+    }
+
+    companion object {
+
+        /**
+         * Conversion from screen rotation to JPEG orientation.
+         */
+        private val ORIENTATIONS = SparseIntArray()
+        private val FRAGMENT_DIALOG = "dialog"
+
+        init {
+            ORIENTATIONS.append(Surface.ROTATION_0, 90)
+            ORIENTATIONS.append(Surface.ROTATION_90, 0)
+            ORIENTATIONS.append(Surface.ROTATION_180, 270)
+            ORIENTATIONS.append(Surface.ROTATION_270, 180)
+        }
+
+        /**
+         * Tag for the [Log].
+         */
+        private val TAG = "Camera2BasicFragment"
+
+        /**
+         * Camera state: Showing camera preview.
+         */
+        private val STATE_PREVIEW = 0
+
+        /**
+         * Camera state: Waiting for the focus to be locked.
+         */
+        private val STATE_WAITING_LOCK = 1
+
+        /**
+         * Camera state: Waiting for the exposure to be precapture state.
+         */
+        private val STATE_WAITING_PRECAPTURE = 2
+
+        /**
+         * Camera state: Waiting for the exposure state to be something other than precapture.
+         */
+        private val STATE_WAITING_NON_PRECAPTURE = 3
+
+        /**
+         * Camera state: Picture was taken.
+         */
+        private val STATE_PICTURE_TAKEN = 4
+
+        /**
+         * Max preview width that is guaranteed by Camera2 API
+         */
+        private val MAX_PREVIEW_WIDTH = 1920
+
+        /**
+         * Max preview height that is guaranteed by Camera2 API
+         */
+        private val MAX_PREVIEW_HEIGHT = 1080
+
+        /**
+         * Given `choices` of `Size`s supported by a camera, choose the smallest one that
+         * is at least as large as the respective texture view size, and that is at most as large as
+         * the respective max size, and whose aspect ratio matches with the specified value. If such
+         * size doesn't exist, choose the largest one that is at most as large as the respective max
+         * size, and whose aspect ratio matches with the specified value.
+         *
+         * @param choices           The list of sizes that the camera supports for the intended
+         *                          output class
+         * @param textureViewWidth  The width of the texture view relative to sensor coordinate
+         * @param textureViewHeight The height of the texture view relative to sensor coordinate
+         * @param maxWidth          The maximum width that can be chosen
+         * @param maxHeight         The maximum height that can be chosen
+         * @param aspectRatio       The aspect ratio
+         * @return The optimal `Size`, or an arbitrary one if none were big enough
+         */
+        @JvmStatic private fun chooseOptimalSize(
+                choices: Array<Size>,
+                textureViewWidth: Int,
+                textureViewHeight: Int,
+                maxWidth: Int,
+                maxHeight: Int,
+                aspectRatio: Size
+        ): Size {
+
+            // Collect the supported resolutions that are at least as big as the preview Surface
+            val bigEnough = ArrayList<Size>()
+            // Collect the supported resolutions that are smaller than the preview Surface
+            val notBigEnough = ArrayList<Size>()
+            val w = aspectRatio.width
+            val h = aspectRatio.height
+            for (option in choices) {
+                if (option.width <= maxWidth && option.height <= maxHeight &&
+                        option.height == option.width * h / w) {
+                    if (option.width >= textureViewWidth && option.height >= textureViewHeight) {
+                        bigEnough.add(option)
+                    } else {
+                        notBigEnough.add(option)
+                    }
+                }
+            }
+
+            // Pick the smallest of those big enough. If there is no one big enough, pick the
+            // largest of those not big enough.
+            if (bigEnough.size > 0) {
+                return Collections.min(bigEnough, CompareSizesByArea())
+            } else if (notBigEnough.size > 0) {
+                return Collections.max(notBigEnough, CompareSizesByArea())
+            } else {
+                Log.e(TAG, "Couldn't find any suitable preview size")
+                return choices[0]
+            }
+        }
+
+        @JvmStatic fun newInstance(): Camera2BasicFragment = Camera2BasicFragment()
+    }
+}
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/CameraActivity.kt b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/CameraActivity.kt
new file mode 100644
index 0000000..e0e85fb
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/CameraActivity.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 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 com.example.android.camera2basic
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+
+class CameraActivity : AppCompatActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_camera)
+        savedInstanceState ?: supportFragmentManager.beginTransaction()
+                .replace(R.id.container, Camera2BasicFragment.newInstance())
+                .commit()
+    }
+
+}
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/CompareSizesByArea.kt b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/CompareSizesByArea.kt
new file mode 100644
index 0000000..83cc2f1
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/CompareSizesByArea.kt
@@ -0,0 +1,17 @@
+package com.example.android.camera2basic
+
+import android.util.Size
+import java.lang.Long.signum
+
+import java.util.Comparator
+
+/**
+ * Compares two `Size`s based on their areas.
+ */
+internal class CompareSizesByArea : Comparator<Size> {
+
+    // We cast here to ensure the multiplications won't overflow
+    override fun compare(lhs: Size, rhs: Size) =
+            signum(lhs.width.toLong() * lhs.height - rhs.width.toLong() * rhs.height)
+
+}
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ConfirmationDialog.kt b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ConfirmationDialog.kt
new file mode 100644
index 0000000..f276c73
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ConfirmationDialog.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 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 com.example.android.camera2basic
+
+import android.Manifest
+import android.app.AlertDialog
+import android.app.Dialog
+import android.os.Bundle
+import android.support.v4.app.DialogFragment
+
+/**
+ * Shows OK/Cancel confirmation dialog about camera permission.
+ */
+class ConfirmationDialog : DialogFragment() {
+
+    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
+            AlertDialog.Builder(activity)
+                    .setMessage(R.string.request_permission)
+                    .setPositiveButton(android.R.string.ok) { _, _ ->
+                        parentFragment.requestPermissions(arrayOf(Manifest.permission.CAMERA),
+                                REQUEST_CAMERA_PERMISSION)
+                    }
+                    .setNegativeButton(android.R.string.cancel) { _, _ ->
+                        parentFragment.activity?.finish()
+                    }
+                    .create()
+}
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/Constants.kt b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/Constants.kt
new file mode 100644
index 0000000..0febbd9
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/Constants.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 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.
+ */
+
+@file:JvmName("Constants")
+
+package com.example.android.camera2basic
+
+@JvmField val REQUEST_CAMERA_PERMISSION = 1
+@JvmField val PIC_FILE_NAME = "pic.jpg"
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ErrorDialog.kt b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ErrorDialog.kt
new file mode 100644
index 0000000..16ecceb
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ErrorDialog.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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 com.example.android.camera2basic
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.os.Bundle
+import android.support.v4.app.DialogFragment
+
+/**
+ * Shows an error message dialog.
+ */
+class ErrorDialog : DialogFragment() {
+
+    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
+            AlertDialog.Builder(activity)
+                    .setMessage(arguments.getString(ARG_MESSAGE))
+                    .setPositiveButton(android.R.string.ok) { _, _ -> activity.finish() }
+                    .create()
+
+    companion object {
+
+        @JvmStatic private val ARG_MESSAGE = "message"
+
+        @JvmStatic fun newInstance(message: String): ErrorDialog = ErrorDialog().apply {
+            arguments = Bundle().apply { putString(ARG_MESSAGE, message) }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ImageSaver.kt b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ImageSaver.kt
new file mode 100644
index 0000000..bf33d4b
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/java/com/example/android/camera2basic/ImageSaver.kt
@@ -0,0 +1,55 @@
+package com.example.android.camera2basic
+
+import android.media.Image
+import android.util.Log
+
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.nio.ByteBuffer
+
+/**
+ * Saves a JPEG [Image] into the specified [File].
+ */
+internal class ImageSaver(
+        /**
+         * The JPEG image
+         */
+        private val image: Image,
+
+        /**
+         * The file we save the image into.
+         */
+        private val file: File
+) : Runnable {
+
+    override fun run() {
+        val buffer = image.planes[0].buffer
+        val bytes = ByteArray(buffer.remaining())
+        buffer.get(bytes)
+        var output: FileOutputStream? = null
+        try {
+            output = FileOutputStream(file).apply {
+                write(bytes)
+            }
+        } catch (e: IOException) {
+            Log.e(TAG, e.toString())
+        } finally {
+            image.close()
+            output?.let {
+                try {
+                    it.close()
+                } catch (e: IOException) {
+                    Log.e(TAG, e.toString())
+                }
+            }
+        }
+    }
+
+    companion object {
+        /**
+         * Tag for the [Log].
+         */
+        private val TAG = "ImageSaver"
+    }
+}
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-hdpi/ic_action_info.png b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..32bd1aa
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..ac6cf27
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-mdpi/ic_action_info.png b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..8efbbf8
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..65f92a5
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_action_info.png b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..ba143ea
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6fd1318
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_action_info.png b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
new file mode 100644
index 0000000..394eb7e
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4513cf2
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/layout-land/fragment_camera2_basic.xml b/media/Camera2Basic/kotlinApp/Application/src/main/res/layout-land/fragment_camera2_basic.xml
new file mode 100644
index 0000000..ec4c66b
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/layout-land/fragment_camera2_basic.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="match_parent"
+    android:layout_height="match_parent">
+
+    <com.example.android.camera2basic.AutoFitTextureView
+        android:id="@+id/texture"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true" />
+
+    <FrameLayout
+        android:id="@+id/control"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentTop="true"
+        android:layout_toEndOf="@id/texture"
+        android:background="@color/control_background"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/picture"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/picture" />
+
+        <ImageButton
+            android:id="@+id/info"
+            style="@android:style/Widget.Material.Light.Button.Borderless"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal|bottom"
+            android:contentDescription="@string/description_info"
+            android:padding="@dimen/image_button_padding"
+            android:src="@drawable/ic_action_info" />
+
+    </FrameLayout>
+
+</RelativeLayout>
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/layout/activity_camera.xml b/media/Camera2Basic/kotlinApp/Application/src/main/res/layout/activity_camera.xml
new file mode 100644
index 0000000..f8bb7f7
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/layout/activity_camera.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/black"
+    tools:context="com.example.android.camera2basic.CameraActivity" />
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/layout/fragment_camera2_basic.xml b/media/Camera2Basic/kotlinApp/Application/src/main/res/layout/fragment_camera2_basic.xml
new file mode 100644
index 0000000..d40b1e2
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/layout/fragment_camera2_basic.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="match_parent"
+    android:layout_height="match_parent">
+
+    <com.example.android.camera2basic.AutoFitTextureView
+        android:id="@+id/texture"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true" />
+
+    <FrameLayout
+        android:id="@+id/control"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/frame_height"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentStart="true"
+        android:background="@color/control_background">
+
+        <Button
+            android:id="@+id/picture"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/picture" />
+
+        <ImageButton
+            android:id="@+id/info"
+            android:contentDescription="@string/description_info"
+            style="@android:style/Widget.Material.Light.Button.Borderless"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical|end"
+            android:padding="@dimen/image_button_padding"
+            android:src="@drawable/ic_action_info" />
+
+    </FrameLayout>
+
+</RelativeLayout>
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/values/colors.xml b/media/Camera2Basic/kotlinApp/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..4b75d2b
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?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>
+    <color name="control_background">#cc4285f4</color>
+</resources>
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/values/dimens.xml b/media/Camera2Basic/kotlinApp/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..3988304
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <dimen name="frame_height">112dp</dimen>
+    <dimen name="image_button_padding">20dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/values/strings.xml b/media/Camera2Basic/kotlinApp/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..eea6611
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/values/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">Camera2Basic</string>
+    <string name="picture">Picture</string>
+    <string name="description_info">Info</string>
+    <string name="request_permission">This sample needs camera permission.</string>
+    <string name="camera_error">This device doesn\'t support Camera2 API.</string>
+    <string name="intro_message">
+        <![CDATA[
+
+
+            This sample demonstrates the basic use of Camera2 API. Check the source code to see how
+            you can display camera preview and take pictures.
+
+
+        ]]>
+    </string>
+</resources>
diff --git a/media/Camera2Basic/kotlinApp/Application/src/main/res/values/styles.xml b/media/Camera2Basic/kotlinApp/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..b76b27d
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/Application/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <style name="MaterialTheme" parent="Theme.AppCompat.Light.NoActionBar">
+        <item name="android:windowFullscreen">true</item>
+    </style>
+</resources>
diff --git a/media/Camera2Basic/kotlinApp/CONTRIB.md b/media/Camera2Basic/kotlinApp/CONTRIB.md
new file mode 100644
index 0000000..14a4fcf
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/CONTRIB.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual CLA]
+    (https://developers.google.com/open-source/cla/individual).
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA]
+    (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+   Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+   you are contributing. Refer to the
+   [Android Code Style Guide]
+   (https://source.android.com/source/code-style.html) for the
+   recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/media/Camera2Basic/kotlinApp/README.md b/media/Camera2Basic/kotlinApp/README.md
new file mode 100644
index 0000000..c006943
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/README.md
@@ -0,0 +1,88 @@
+Android Camera2Basic Sample (Kotlin)
+====================================
+
+This sample demonstrates how to use basic functionalities of Camera2
+API. You can learn how to iterate through characteristics of all the
+cameras attached to the device, display a camera preview, and take
+pictures.
+
+Introduction
+------------
+
+The [Camera2 API][1] provides an interface to individual camera
+devices connected to an Android device. It replaces the deprecated
+Camera class.
+
+Use [getCameraIdList][2] to get a list of all the available
+cameras. You can then use [getCameraCharacteristics][3] and find the
+best camera that suits your need (front/rear facing, resolution etc).
+
+Create an instance of [CameraDevice.StateCallback][4] and open a
+camera. It is ready to start camera preview when the camera is opened.
+
+This sample uses TextureView to show the camera preview. Create a
+[CameraCaptureSession][5] and set a repeating [CaptureRequest][6] to it.
+
+Still image capture takes several steps. First, you need to lock the
+focus of the camera by updating the CaptureRequest for the camera
+preview. Then, in a similar way, you need to run a precapture
+sequence. After that, it is ready to capture a picture. Create a new
+CaptureRequest and call [capture][7]. Don't forget to unlock the focus
+when you are done.
+
+[1]: https://developer.android.com/reference/android/hardware/camera2/package-summary.html
+[2]: https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList()
+[3]: https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraCharacteristics(java.lang.String)
+[4]: https://developer.android.com/reference/android/hardware/camera2/CameraDevice.StateCallback.html
+[5]: https://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession.html
+[6]: https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html
+[7]: https://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession.html#capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler)
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Support Repository
+
+Screenshots
+-------------
+
+<img src="screenshots/main.png" height="400" alt="Screenshot"/>
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-Camera2Basic
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2017 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/media/Camera2Basic/kotlinApp/build.gradle b/media/Camera2Basic/kotlinApp/build.gradle
new file mode 100644
index 0000000..829a025
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/build.gradle
@@ -0,0 +1,22 @@
+buildscript {
+  ext.kotlin_version = '1.1.51'
+  repositories {
+    google()
+    jcenter()
+  }
+  dependencies {
+    classpath 'com.android.tools.build:gradle:3.0.0'
+    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+  }
+}
+
+allprojects {
+  repositories {
+    google()
+    jcenter()
+  }
+}
+
+task clean(type: Delete) {
+  delete rootProject.buildDir
+}
diff --git a/media/Camera2Basic/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/media/Camera2Basic/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/media/Camera2Basic/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..32d89d5
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Sep 20 14:52:30 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/media/Camera2Basic/kotlinApp/gradlew b/media/Camera2Basic/kotlinApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/media/Camera2Basic/kotlinApp/gradlew.bat b/media/Camera2Basic/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/media/Camera2Basic/kotlinApp/packaging.yaml b/media/Camera2Basic/kotlinApp/packaging.yaml
new file mode 100644
index 0000000..3f8852d
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/packaging.yaml
@@ -0,0 +1,14 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [Media]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-Camera2Basic
+level:        BEGINNER
+icon:         screenshots/icon-web.png
+license:      apache2
diff --git a/media/Camera2Basic/kotlinApp/screenshots/icon-web.png b/media/Camera2Basic/kotlinApp/screenshots/icon-web.png
new file mode 100644
index 0000000..d9bd4c4
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/screenshots/icon-web.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/screenshots/main.png b/media/Camera2Basic/kotlinApp/screenshots/main.png
new file mode 100644
index 0000000..47419eb
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/screenshots/main.png
Binary files differ
diff --git a/media/Camera2Basic/kotlinApp/settings.gradle b/media/Camera2Basic/kotlinApp/settings.gradle
new file mode 100644
index 0000000..9464a35
--- /dev/null
+++ b/media/Camera2Basic/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'Application'
diff --git a/media/Camera2Raw/Application/src/main/java/com/example/android/camera2raw/Camera2RawFragment.java b/media/Camera2Raw/Application/src/main/java/com/example/android/camera2raw/Camera2RawFragment.java
index aed2160..d28c7fc 100644
--- a/media/Camera2Raw/Application/src/main/java/com/example/android/camera2raw/Camera2RawFragment.java
+++ b/media/Camera2Raw/Application/src/main/java/com/example/android/camera2raw/Camera2RawFragment.java
@@ -1743,7 +1743,7 @@
 
         // Calculate desired JPEG orientation relative to camera orientation to make
         // the image upright relative to the device orientation
-        return (sensorOrientation + deviceOrientation + 360) % 360;
+        return (sensorOrientation - deviceOrientation + 360) % 360;
     }
 
     /**
diff --git a/media/Camera2Raw/gradle/wrapper/gradle-wrapper.properties b/media/Camera2Raw/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/media/Camera2Raw/gradle/wrapper/gradle-wrapper.properties
+++ b/media/Camera2Raw/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/Camera2Video/gradle/wrapper/gradle-wrapper.properties b/media/Camera2Video/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/media/Camera2Video/gradle/wrapper/gradle-wrapper.properties
+++ b/media/Camera2Video/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/Camera2Video/kotlinApp/.google/packaging.yaml b/media/Camera2Video/kotlinApp/.google/packaging.yaml
new file mode 100644
index 0000000..583ad7f
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/.google/packaging.yaml
@@ -0,0 +1,19 @@
+
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [Media]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-Camera2Video
+level:        ADVANCED
+icon:         screenshots/icon-web.png
+apiRefs:
+    - android:android.hardware.camera2.CameraCaptureSession
+    - android:android.hardware.camera2.CameraDevice
+    - android:android.view.TextureView
+license: apache2
diff --git a/media/Camera2Video/kotlinApp/Application/build.gradle b/media/Camera2Video/kotlinApp/Application/build.gradle
new file mode 100644
index 0000000..1d01e7e
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion 27
+    defaultConfig {
+        applicationId "com.example.android.camera2video"
+        minSdkVersion 24
+        targetSdkVersion 27
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:27.0.2"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+}
\ No newline at end of file
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/AndroidManifest.xml b/media/Camera2Video/kotlinApp/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..acc9d11
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.camera2video">
+
+    <uses-permission android:name="android.permission.CAMERA"/>
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+    <application
+        android:allowBackup="false"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/MaterialTheme">
+
+        <activity android:name=".CameraActivity"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/AutoFitTextureView.kt b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/AutoFitTextureView.kt
new file mode 100644
index 0000000..a871bd8
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/AutoFitTextureView.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 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 com.example.android.camera2video
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.TextureView
+import android.view.View
+
+/**
+ * A [TextureView] that can be adjusted to a specified aspect ratio.
+ */
+class AutoFitTextureView @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyle: Int = 0
+) : TextureView(context, attrs, defStyle) {
+
+    private var ratioWidth = 0
+    private var ratioHeight = 0
+
+    /**
+     * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
+     * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
+     * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
+     *
+     * @param width  Relative horizontal size
+     * @param height Relative vertical size
+     */
+    fun setAspectRatio(width: Int, height: Int) {
+        if (width < 0 || height < 0) {
+            throw IllegalArgumentException("Size cannot be negative.")
+        }
+        ratioWidth = width
+        ratioHeight = height
+        requestLayout()
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        val width = View.MeasureSpec.getSize(widthMeasureSpec)
+        val height = View.MeasureSpec.getSize(heightMeasureSpec)
+        if (ratioWidth == 0 || ratioHeight == 0) {
+            setMeasuredDimension(width, height)
+        } else {
+            if (width < ((height * ratioWidth) / ratioHeight)) {
+                setMeasuredDimension(width, (width * ratioHeight) / ratioWidth)
+            } else {
+                setMeasuredDimension((height * ratioWidth) / ratioHeight, height)
+            }
+        }
+    }
+
+}
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.kt b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.kt
new file mode 100644
index 0000000..a361c0b
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.kt
@@ -0,0 +1,627 @@
+/*
+ * Copyright 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 com.example.android.camera2video
+
+import android.annotation.SuppressLint
+import android.app.AlertDialog
+import android.content.Context
+import android.content.pm.PackageManager.PERMISSION_GRANTED
+import android.content.res.Configuration
+import android.graphics.Matrix
+import android.graphics.RectF
+import android.graphics.SurfaceTexture
+import android.hardware.camera2.CameraAccessException
+import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP
+import android.hardware.camera2.CameraCharacteristics.SENSOR_ORIENTATION
+import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW
+import android.hardware.camera2.CameraDevice.TEMPLATE_RECORD
+import android.hardware.camera2.CameraManager
+import android.hardware.camera2.CameraMetadata
+import android.hardware.camera2.CaptureRequest
+import android.media.MediaRecorder
+import android.os.Bundle
+import android.os.Handler
+import android.os.HandlerThread
+import android.support.v4.app.ActivityCompat
+import android.support.v4.app.Fragment
+import android.support.v4.app.FragmentActivity
+import android.support.v4.content.ContextCompat.checkSelfPermission
+import android.util.Log
+import android.util.Size
+import android.util.SparseIntArray
+import android.view.LayoutInflater
+import android.view.Surface
+import android.view.TextureView
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.Toast
+import android.widget.Toast.LENGTH_SHORT
+import java.io.IOException
+import java.util.Collections
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
+import kotlin.collections.ArrayList
+
+class Camera2VideoFragment : Fragment(), View.OnClickListener,
+        ActivityCompat.OnRequestPermissionsResultCallback {
+
+    private val FRAGMENT_DIALOG = "dialog"
+    private val TAG = "Camera2VideoFragment"
+    private val SENSOR_ORIENTATION_DEFAULT_DEGREES = 90
+    private val SENSOR_ORIENTATION_INVERSE_DEGREES = 270
+    private val DEFAULT_ORIENTATIONS = SparseIntArray().apply {
+        append(Surface.ROTATION_0, 90)
+        append(Surface.ROTATION_90, 0)
+        append(Surface.ROTATION_180, 270)
+        append(Surface.ROTATION_270, 180)
+    }
+    private val INVERSE_ORIENTATIONS = SparseIntArray().apply {
+        append(Surface.ROTATION_0, 270)
+        append(Surface.ROTATION_90, 180)
+        append(Surface.ROTATION_180, 90)
+        append(Surface.ROTATION_270, 0)
+    }
+
+    /**
+     * [TextureView.SurfaceTextureListener] handles several lifecycle events on a
+     * [TextureView].
+     */
+    private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
+
+        override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) {
+            openCamera(width, height)
+        }
+
+        override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {
+            configureTransform(width, height)
+        }
+
+        override fun onSurfaceTextureDestroyed(surfaceTexture: SurfaceTexture) = true
+
+        override fun onSurfaceTextureUpdated(surfaceTexture: SurfaceTexture) = Unit
+
+    }
+
+    /**
+     * An [AutoFitTextureView] for camera preview.
+     */
+    private lateinit var textureView: AutoFitTextureView
+
+    /**
+     * Button to record video
+     */
+    private lateinit var videoButton: Button
+
+    /**
+     * A reference to the opened [android.hardware.camera2.CameraDevice].
+     */
+    private var cameraDevice: CameraDevice? = null
+
+    /**
+     * A reference to the current [android.hardware.camera2.CameraCaptureSession] for
+     * preview.
+     */
+    private var captureSession: CameraCaptureSession? = null
+
+    /**
+     * The [android.util.Size] of camera preview.
+     */
+    private lateinit var previewSize: Size
+
+    /**
+     * The [android.util.Size] of video recording.
+     */
+    private lateinit var videoSize: Size
+
+    /**
+     * Whether the app is recording video now
+     */
+    private var isRecordingVideo = false
+
+    /**
+     * An additional thread for running tasks that shouldn't block the UI.
+     */
+    private var backgroundThread: HandlerThread? = null
+
+    /**
+     * A [Handler] for running tasks in the background.
+     */
+    private var backgroundHandler: Handler? = null
+
+    /**
+     * A [Semaphore] to prevent the app from exiting before closing the camera.
+     */
+    private val cameraOpenCloseLock = Semaphore(1)
+
+    /**
+     * [CaptureRequest.Builder] for the camera preview
+     */
+    private lateinit var previewRequestBuilder: CaptureRequest.Builder
+
+    /**
+     * Orientation of the camera sensor
+     */
+    private var sensorOrientation = 0
+
+    /**
+     * [CameraDevice.StateCallback] is called when [CameraDevice] changes its status.
+     */
+    private val stateCallback = object : CameraDevice.StateCallback() {
+
+        override fun onOpened(cameraDevice: CameraDevice) {
+            cameraOpenCloseLock.release()
+            this@Camera2VideoFragment.cameraDevice = cameraDevice
+            startPreview()
+            configureTransform(textureView.width, textureView.height)
+        }
+
+        override fun onDisconnected(cameraDevice: CameraDevice) {
+            cameraOpenCloseLock.release()
+            cameraDevice.close()
+            this@Camera2VideoFragment.cameraDevice = null
+        }
+
+        override fun onError(cameraDevice: CameraDevice, error: Int) {
+            cameraOpenCloseLock.release()
+            cameraDevice.close()
+            this@Camera2VideoFragment.cameraDevice = null
+            activity?.finish()
+        }
+
+    }
+
+    /**
+     * Output file for video
+     */
+    private var nextVideoAbsolutePath: String? = null
+
+    private var mediaRecorder: MediaRecorder? = null
+
+    override fun onCreateView(inflater: LayoutInflater,
+                              container: ViewGroup?,
+                              savedInstanceState: Bundle?
+    ): View? = inflater.inflate(R.layout.fragment_camera2_video, container, false)
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        textureView = view.findViewById(R.id.texture)
+        videoButton = view.findViewById<Button>(R.id.video).also {
+            it.setOnClickListener(this)
+        }
+        view.findViewById<View>(R.id.info).setOnClickListener(this)
+    }
+
+    override fun onResume() {
+        super.onResume()
+        startBackgroundThread()
+
+        // When the screen is turned off and turned back on, the SurfaceTexture is already
+        // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
+        // a camera and start preview from here (otherwise, we wait until the surface is ready in
+        // the SurfaceTextureListener).
+        if (textureView.isAvailable) {
+            openCamera(textureView.width, textureView.height)
+        } else {
+            textureView.surfaceTextureListener = surfaceTextureListener
+        }
+    }
+
+    override fun onPause() {
+        closeCamera()
+        stopBackgroundThread()
+        super.onPause()
+    }
+
+    override fun onClick(view: View) {
+        when (view.id) {
+            R.id.video -> if (isRecordingVideo) stopRecordingVideo() else startRecordingVideo()
+            R.id.info -> {
+                if (activity != null) {
+                    AlertDialog.Builder(activity)
+                            .setMessage(R.string.intro_message)
+                            .setPositiveButton(android.R.string.ok, null)
+                            .show()
+                }
+            }
+        }
+    }
+
+    /**
+     * Starts a background thread and its [Handler].
+     */
+    private fun startBackgroundThread() {
+        backgroundThread = HandlerThread("CameraBackground")
+        backgroundThread?.start()
+        backgroundHandler = Handler(backgroundThread?.looper)
+    }
+
+    /**
+     * Stops the background thread and its [Handler].
+     */
+    private fun stopBackgroundThread() {
+        backgroundThread?.quitSafely()
+        try {
+            backgroundThread?.join()
+            backgroundThread = null
+            backgroundHandler = null
+        } catch (e: InterruptedException) {
+            Log.e(TAG, e.toString())
+        }
+    }
+
+    /**
+     * Gets whether you should show UI with rationale for requesting permissions.
+     *
+     * @param permissions The permissions your app wants to request.
+     * @return Whether you can show permission rationale UI.
+     */
+    private fun shouldShowRequestPermissionRationale(permissions: Array<String>) =
+            permissions.any { shouldShowRequestPermissionRationale(it) }
+
+    /**
+     * Requests permissions needed for recording video.
+     */
+    private fun requestVideoPermissions() {
+        if (shouldShowRequestPermissionRationale(VIDEO_PERMISSIONS)) {
+            ConfirmationDialog().show(childFragmentManager, FRAGMENT_DIALOG)
+        } else {
+            requestPermissions(VIDEO_PERMISSIONS, REQUEST_VIDEO_PERMISSIONS)
+        }
+    }
+
+    override fun onRequestPermissionsResult(
+            requestCode: Int,
+            permissions: Array<String>,
+            grantResults: IntArray
+    ) {
+        if (requestCode == REQUEST_VIDEO_PERMISSIONS) {
+            if (grantResults.size == VIDEO_PERMISSIONS.size) {
+                for (result in grantResults) {
+                    if (result != PERMISSION_GRANTED) {
+                        ErrorDialog.newInstance(getString(R.string.permission_request))
+                                .show(childFragmentManager, FRAGMENT_DIALOG)
+                        break
+                    }
+                }
+            } else {
+                ErrorDialog.newInstance(getString(R.string.permission_request))
+                        .show(childFragmentManager, FRAGMENT_DIALOG)
+            }
+        } else {
+            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+        }
+    }
+
+    private fun hasPermissionsGranted(permissions: Array<String>) =
+            permissions.none {
+                checkSelfPermission((activity as FragmentActivity), it) != PERMISSION_GRANTED
+            }
+
+    /**
+     * Tries to open a [CameraDevice]. The result is listened by [stateCallback].
+     *
+     * Lint suppression - permission is checked in [hasPermissionsGranted]
+     */
+    @SuppressLint("MissingPermission")
+    private fun openCamera(width: Int, height: Int) {
+        if (!hasPermissionsGranted(VIDEO_PERMISSIONS)) {
+            requestVideoPermissions()
+            return
+        }
+
+        val cameraActivity = activity
+        if (cameraActivity == null || cameraActivity.isFinishing) return
+
+        val manager = cameraActivity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
+        try {
+            if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
+                throw RuntimeException("Time out waiting to lock camera opening.")
+            }
+            val cameraId = manager.cameraIdList[0]
+
+            // Choose the sizes for camera preview and video recording
+            val characteristics = manager.getCameraCharacteristics(cameraId)
+            val map = characteristics.get(SCALER_STREAM_CONFIGURATION_MAP) ?:
+                    throw RuntimeException("Cannot get available preview/video sizes")
+            sensorOrientation = characteristics.get(SENSOR_ORIENTATION)
+            videoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder::class.java))
+            previewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture::class.java),
+                    width, height, videoSize)
+
+            if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+                textureView.setAspectRatio(previewSize.width, previewSize.height)
+            } else {
+                textureView.setAspectRatio(previewSize.height, previewSize.width)
+            }
+            configureTransform(width, height)
+            mediaRecorder = MediaRecorder()
+            manager.openCamera(cameraId, stateCallback, null)
+        } catch (e: CameraAccessException) {
+            showToast("Cannot access the camera.")
+            cameraActivity.finish()
+        } catch (e: NullPointerException) {
+            // Currently an NPE is thrown when the Camera2API is used but not supported on the
+            // device this code runs.
+            ErrorDialog.newInstance(getString(R.string.camera_error))
+                    .show(childFragmentManager, FRAGMENT_DIALOG)
+        } catch (e: InterruptedException) {
+            throw RuntimeException("Interrupted while trying to lock camera opening.")
+        }
+    }
+
+    /**
+     * Close the [CameraDevice].
+     */
+    private fun closeCamera() {
+        try {
+            cameraOpenCloseLock.acquire()
+            closePreviewSession()
+            cameraDevice?.close()
+            cameraDevice = null
+            mediaRecorder?.release()
+            mediaRecorder = null
+        } catch (e: InterruptedException) {
+            throw RuntimeException("Interrupted while trying to lock camera closing.", e)
+        } finally {
+            cameraOpenCloseLock.release()
+        }
+    }
+
+    /**
+     * Start the camera preview.
+     */
+    private fun startPreview() {
+        if (cameraDevice == null || !textureView.isAvailable) return
+
+        try {
+            closePreviewSession()
+            val texture = textureView.surfaceTexture
+            texture.setDefaultBufferSize(previewSize.width, previewSize.height)
+            previewRequestBuilder = cameraDevice!!.createCaptureRequest(TEMPLATE_PREVIEW)
+
+            val previewSurface = Surface(texture)
+            previewRequestBuilder.addTarget(previewSurface)
+
+            cameraDevice?.createCaptureSession(listOf(previewSurface),
+                    object : CameraCaptureSession.StateCallback() {
+
+                        override fun onConfigured(session: CameraCaptureSession) {
+                            captureSession = session
+                            updatePreview()
+                        }
+
+                        override fun onConfigureFailed(session: CameraCaptureSession) {
+                            if (activity != null) showToast("Failed")
+                        }
+                    }, backgroundHandler)
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        }
+
+    }
+
+    /**
+     * Update the camera preview. [startPreview] needs to be called in advance.
+     */
+    private fun updatePreview() {
+        if (cameraDevice == null) return
+
+        try {
+            setUpCaptureRequestBuilder(previewRequestBuilder)
+            HandlerThread("CameraPreview").start()
+            captureSession?.setRepeatingRequest(previewRequestBuilder.build(),
+                    null, backgroundHandler)
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        }
+
+    }
+
+    private fun setUpCaptureRequestBuilder(builder: CaptureRequest.Builder?) {
+        builder?.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
+    }
+
+    /**
+     * Configures the necessary [android.graphics.Matrix] transformation to `textureView`.
+     * This method should not to be called until the camera preview size is determined in
+     * openCamera, or until the size of `textureView` is fixed.
+     *
+     * @param viewWidth  The width of `textureView`
+     * @param viewHeight The height of `textureView`
+     */
+    private fun configureTransform(viewWidth: Int, viewHeight: Int) {
+        activity ?: return
+        val rotation = (activity as FragmentActivity).windowManager.defaultDisplay.rotation
+        val matrix = Matrix()
+        val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
+        val bufferRect = RectF(0f, 0f, previewSize.height.toFloat(), previewSize.width.toFloat())
+        val centerX = viewRect.centerX()
+        val centerY = viewRect.centerY()
+
+        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY())
+            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL)
+            val scale = Math.max(
+                    viewHeight.toFloat() / previewSize.height,
+                    viewWidth.toFloat() / previewSize.width)
+            with(matrix) {
+                postScale(scale, scale, centerX, centerY)
+                postRotate((90 * (rotation - 2)).toFloat(), centerX, centerY)
+            }
+        }
+        textureView.setTransform(matrix)
+    }
+
+    @Throws(IOException::class)
+    private fun setUpMediaRecorder() {
+        val cameraActivity = activity ?: return
+
+        if (nextVideoAbsolutePath.isNullOrEmpty()) {
+            nextVideoAbsolutePath = getVideoFilePath(cameraActivity)
+        }
+
+        val rotation = cameraActivity.windowManager.defaultDisplay.rotation
+        when (sensorOrientation) {
+            SENSOR_ORIENTATION_DEFAULT_DEGREES ->
+                mediaRecorder?.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation))
+            SENSOR_ORIENTATION_INVERSE_DEGREES ->
+                mediaRecorder?.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation))
+        }
+
+        mediaRecorder?.apply {
+            setAudioSource(MediaRecorder.AudioSource.MIC)
+            setVideoSource(MediaRecorder.VideoSource.SURFACE)
+            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
+            setOutputFile(nextVideoAbsolutePath)
+            setVideoEncodingBitRate(10000000)
+            setVideoFrameRate(30)
+            setVideoSize(videoSize.width, videoSize.height)
+            setVideoEncoder(MediaRecorder.VideoEncoder.H264)
+            setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
+            prepare()
+        }
+    }
+
+    private fun getVideoFilePath(context: Context?): String {
+        val filename = "${System.currentTimeMillis()}.mp4"
+        val dir = context?.getExternalFilesDir(null)
+
+        return if (dir == null) {
+            filename
+        } else {
+            "${dir.absolutePath}/$filename"
+        }
+    }
+
+    private fun startRecordingVideo() {
+        if (cameraDevice == null || !textureView.isAvailable) return
+
+        try {
+            closePreviewSession()
+            setUpMediaRecorder()
+            val texture = textureView.surfaceTexture.apply {
+                setDefaultBufferSize(previewSize.width, previewSize.height)
+            }
+
+            // Set up Surface for camera preview and MediaRecorder
+            val previewSurface = Surface(texture)
+            val recorderSurface = mediaRecorder!!.surface
+            val surfaces = ArrayList<Surface>().apply {
+                add(previewSurface)
+                add(recorderSurface)
+            }
+            previewRequestBuilder = cameraDevice!!.createCaptureRequest(TEMPLATE_RECORD).apply {
+                addTarget(previewSurface)
+                addTarget(recorderSurface)
+            }
+
+            // Start a capture session
+            // Once the session starts, we can update the UI and start recording
+            cameraDevice?.createCaptureSession(surfaces,
+                    object : CameraCaptureSession.StateCallback() {
+
+                override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
+                    captureSession = cameraCaptureSession
+                    updatePreview()
+                    activity?.runOnUiThread {
+                        videoButton.setText(R.string.stop)
+                        isRecordingVideo = true
+                        mediaRecorder?.start()
+                    }
+                }
+
+                override fun onConfigureFailed(cameraCaptureSession: CameraCaptureSession) {
+                    if (activity != null) showToast("Failed")
+                }
+            }, backgroundHandler)
+        } catch (e: CameraAccessException) {
+            Log.e(TAG, e.toString())
+        } catch (e: IOException) {
+            Log.e(TAG, e.toString())
+        }
+
+    }
+
+    private fun closePreviewSession() {
+        captureSession?.close()
+        captureSession = null
+    }
+
+    private fun stopRecordingVideo() {
+        isRecordingVideo = false
+        videoButton.setText(R.string.record)
+        mediaRecorder?.apply {
+            stop()
+            reset()
+        }
+
+        if (activity != null) showToast("Video saved: $nextVideoAbsolutePath")
+        nextVideoAbsolutePath = null
+        startPreview()
+    }
+
+    private fun showToast(message : String) = Toast.makeText(activity, message, LENGTH_SHORT).show()
+
+    /**
+     * In this sample, we choose a video size with 3x4 aspect ratio. Also, we don't use sizes
+     * larger than 1080p, since MediaRecorder cannot handle such a high-resolution video.
+     *
+     * @param choices The list of available sizes
+     * @return The video size
+     */
+    private fun chooseVideoSize(choices: Array<Size>) = choices.firstOrNull {
+        it.width == it.height * 4 / 3 && it.width <= 1080 } ?: choices[choices.size - 1]
+
+    /**
+     * Given [choices] of [Size]s supported by a camera, chooses the smallest one whose
+     * width and height are at least as large as the respective requested values, and whose aspect
+     * ratio matches with the specified value.
+     *
+     * @param choices     The list of sizes that the camera supports for the intended output class
+     * @param width       The minimum desired width
+     * @param height      The minimum desired height
+     * @param aspectRatio The aspect ratio
+     * @return The optimal [Size], or an arbitrary one if none were big enough
+     */
+    private fun chooseOptimalSize(
+            choices: Array<Size>,
+            width: Int,
+            height: Int,
+            aspectRatio: Size
+    ): Size {
+
+        // Collect the supported resolutions that are at least as big as the preview Surface
+        val w = aspectRatio.width
+        val h = aspectRatio.height
+        val bigEnough = choices.filter {
+            it.height == it.width * h / w && it.width >= width && it.height >= height }
+
+        // Pick the smallest of those, assuming we found any
+        return if (bigEnough.isNotEmpty()) {
+            Collections.min(bigEnough, CompareSizesByArea())
+        } else {
+            choices[0]
+        }
+    }
+
+    companion object {
+        fun newInstance(): Camera2VideoFragment = Camera2VideoFragment()
+    }
+
+}
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/CameraActivity.kt b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/CameraActivity.kt
new file mode 100644
index 0000000..3392ca3
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/CameraActivity.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 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 com.example.android.camera2video
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+
+class CameraActivity : AppCompatActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_camera)
+        savedInstanceState ?: supportFragmentManager.beginTransaction()
+                    .replace(R.id.container, Camera2VideoFragment.newInstance())
+                    .commit()
+    }
+
+}
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/CompareSizesByArea.kt b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/CompareSizesByArea.kt
new file mode 100644
index 0000000..c04b5d8
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/CompareSizesByArea.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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 com.example.android.camera2video
+
+import android.util.Size
+import java.lang.Long.signum
+
+/**
+ * Compare two [Size]s based on their areas.
+ */
+class CompareSizesByArea : Comparator<Size> {
+
+    // We cast here to ensure the multiplications won't overflow
+    override fun compare(lhs: Size, rhs: Size) =
+            signum(lhs.width.toLong() * lhs.height - rhs.width.toLong() * rhs.height)
+}
\ No newline at end of file
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/ConfirmationDialog.kt b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/ConfirmationDialog.kt
new file mode 100644
index 0000000..28ab473
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/ConfirmationDialog.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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 com.example.android.camera2video
+
+import android.app.AlertDialog
+import android.os.Bundle
+import android.support.v4.app.DialogFragment
+
+/**
+ * Shows OK/Cancel confirmation dialog about camera permission.
+ */
+class ConfirmationDialog : DialogFragment() {
+
+    override fun onCreateDialog(savedInstanceState: Bundle?) =
+            AlertDialog.Builder(activity)
+                    .setMessage(R.string.permission_request)
+                    .setPositiveButton(android.R.string.ok) { _, _ ->
+                        parentFragment?.requestPermissions(VIDEO_PERMISSIONS,
+                                REQUEST_VIDEO_PERMISSIONS)
+                    }
+                    .setNegativeButton(android.R.string.cancel) { _,_ ->
+                        parentFragment?.activity?.finish()
+                    }
+                    .create()
+
+}
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/Constants.kt b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/Constants.kt
new file mode 100644
index 0000000..b1945d8
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/Constants.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 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.
+ */
+
+@file:JvmName("Constants")
+
+package com.example.android.camera2video
+
+import android.Manifest
+
+val REQUEST_VIDEO_PERMISSIONS = 1
+val VIDEO_PERMISSIONS = arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
\ No newline at end of file
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/ErrorDialog.kt b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/ErrorDialog.kt
new file mode 100644
index 0000000..9078375
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/java/com/example/android/camera2video/ErrorDialog.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 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 com.example.android.camera2video
+
+import android.app.AlertDialog
+import android.os.Bundle
+import android.support.v4.app.DialogFragment
+
+/**
+ * Shows an error message dialog.
+ */
+class ErrorDialog : DialogFragment() {
+    private val ARG_MESSAGE = "message"
+
+    override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog =
+            AlertDialog.Builder(activity)
+                    .setMessage(arguments?.getString(ARG_MESSAGE))
+                    .setPositiveButton(android.R.string.ok)  { _, _ -> activity?.finish() }
+                    .create()
+
+    companion object {
+        fun newInstance(message: String) = ErrorDialog().apply {
+            arguments = Bundle().apply { putString(ARG_MESSAGE, message) }
+        }
+    }
+
+}
+
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-hdpi/ic_action_info.png b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..32bd1aa
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..88bc107
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-mdpi/ic_action_info.png b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..8efbbf8
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..28a5a42
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_action_info.png b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..ba143ea
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..2811666
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_action_info.png b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
new file mode 100644
index 0000000..394eb7e
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..0e8ab46
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/layout-land/fragment_camera2_video.xml b/media/Camera2Video/kotlinApp/Application/src/main/res/layout-land/fragment_camera2_video.xml
new file mode 100644
index 0000000..bcb53b2
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/layout-land/fragment_camera2_video.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.example.android.camera2video.AutoFitTextureView
+        android:id="@+id/texture"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true" />
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentTop="true"
+        android:layout_below="@id/texture"
+        android:layout_toEndOf="@id/texture"
+        android:background="@color/fragment_background"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/video"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/record" />
+
+        <ImageButton
+            android:id="@+id/info"
+            style="@android:style/Widget.Material.Light.Button.Borderless"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal|bottom"
+            android:contentDescription="@string/description_info"
+            android:padding="@dimen/button_padding"
+            android:src="@drawable/ic_action_info" />
+
+    </FrameLayout>
+
+</RelativeLayout>
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/layout/activity_camera.xml b/media/Camera2Video/kotlinApp/Application/src/main/res/layout/activity_camera.xml
new file mode 100644
index 0000000..f0c74bb
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/layout/activity_camera.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/activity_background"
+    tools:context="com.example.android.camera2video.CameraActivity" />
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/layout/fragment_camera2_video.xml b/media/Camera2Video/kotlinApp/Application/src/main/res/layout/fragment_camera2_video.xml
new file mode 100644
index 0000000..9c5f961
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/layout/fragment_camera2_video.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.example.android.camera2video.AutoFitTextureView
+        android:id="@+id/texture"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true" />
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentStart="true"
+        android:layout_below="@id/texture"
+        android:background="@color/fragment_background">
+
+        <Button
+            android:id="@+id/video"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/record" />
+
+        <ImageButton
+            android:id="@+id/info"
+            android:contentDescription="@string/description_info"
+            style="@android:style/Widget.Material.Light.Button.Borderless"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical|end"
+            android:padding="@dimen/button_padding"
+            android:src="@drawable/ic_action_info" />
+
+    </FrameLayout>
+
+</RelativeLayout>
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml b/media/Camera2Video/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml
new file mode 100644
index 0000000..68b73c2
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+    <!-- Activity themes -->
+    <style name="Theme.Base" parent="android:Theme.Material.Light">
+    </style>
+
+</resources>
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/values/base-strings.xml b/media/Camera2Video/kotlinApp/Application/src/main/res/values/base-strings.xml
new file mode 100644
index 0000000..e9c9f19
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/values/base-strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <string name="app_name">Camera2Video</string>
+    <string name="intro_message">
+        <![CDATA[
+            This sample demonstrates how to record video using Camera2 API.
+        ]]>
+    </string>
+</resources>
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/values/colors.xml b/media/Camera2Video/kotlinApp/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..d26b729
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <color name="activity_background">#000</color>
+    <color name="fragment_background">#4285f4</color>
+</resources>
\ No newline at end of file
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/values/dimens.xml b/media/Camera2Video/kotlinApp/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..a6ceecb
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <dimen name="button_padding">20dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/values/strings.xml b/media/Camera2Video/kotlinApp/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..8c4b723
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <string name="record">Record</string>
+    <string name="stop">Stop</string>
+    <string name="description_info">Info</string>
+    <string name="permission_request">This sample needs permission for camera and audio recording.</string>
+    <string name="camera_error">This device doesn\'t support Camera2 API.</string>
+</resources>
\ No newline at end of file
diff --git a/media/Camera2Video/kotlinApp/Application/src/main/res/values/styles.xml b/media/Camera2Video/kotlinApp/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..4da70d6
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/Application/src/main/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+
+    <style name="MaterialTheme" parent="Theme.AppCompat.Light.NoActionBar">
+        <item name="android:windowFullscreen">true</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/media/Camera2Video/kotlinApp/CONTRIB.md b/media/Camera2Video/kotlinApp/CONTRIB.md
new file mode 100644
index 0000000..14a4fcf
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/CONTRIB.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual CLA]
+    (https://developers.google.com/open-source/cla/individual).
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA]
+    (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+   Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+   you are contributing. Refer to the
+   [Android Code Style Guide]
+   (https://source.android.com/source/code-style.html) for the
+   recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/media/Camera2Video/kotlinApp/README.md b/media/Camera2Video/kotlinApp/README.md
new file mode 100644
index 0000000..71aa31e
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/README.md
@@ -0,0 +1,92 @@
+
+Android Camera2Video Sample (Kotlin)
+====================================
+
+This sample shows how to record video using the new Camera2 API in Android Lollipop.
+
+Introduction
+------------
+
+Android Lollipop introduced a new camera API, called camera2. This sample uses [CameraDevice][1]
+and [CameraCaptureSession][2] to record video. It also uses a custom [TextureView][3] to render the output.
+
+The main steps are:
+
+1. Create a custom TextureView class and add it to the layout. The purpose of the custom TextureView is
+to be able to draw itself according to an aspect ratio, which is set via a public method. Additionally,
+the `onMeasure(int widthMeasureSpec, int heightMeasureSpec)` method is overridden, using the aspect ratio.
+2. Implement a `TextureView.SurfaceTextureListener` on your TextureView, and override its
+`onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height)` method to calculate
+the matrix to apply to the TextureView so the camera output fits. Use the method `setTransform(matrix)` on
+the TextureView.
+3. Implement a [`CameraDevice.StateCallback`][4] to receive events about changes of the state of the
+camera device. Override its methods to set your CameraDevice instance, start the preview, and stop
+and release the camera.
+4. When starting the preview, set up the MediaRecorder to accept video format.
+5. Then, set up a [`CaptureRequest.Builder`][5] using `createCaptureRequest(CameraDevice.TEMPLATE_RECORD)`
+on your CameraDevice instance.
+6. Then, implement a [`CameraCaptureSession.StateCallback`][6], using the method
+`createCaptureSession(surfaces, new CameraCaptureSession.StateCallback(){})` on your CameraDevice instance,
+where `surfaces` is a list consisting of the surface view of your TextureView and the surface of
+your MediaRecorder instance.
+7. Use `start()` and `stop()` methods on your MediaRecorder instance to actually start and stop the recording.
+8. Lastly, set up and clean up your camera device in `onResume()` and `onPause()`.
+
+
+[1]: https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html
+[2]: http://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession.html
+[3]: http://developer.android.com/reference/android/view/TextureView.html
+[4]: https://developer.android.com/reference/android/hardware/camera2/CameraDevice.StateCallback.html
+[5]: http://developer.android.com/reference/android/hardware/camera2/CaptureRequest.Builder.html
+[6]: http://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession.StateCallback.html
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Support Repository
+
+Screenshots
+-------------
+
+<img src="screenshots/1-launch.png" height="400" alt="Screenshot"/>
+<img src="screenshots/2-record.png" height="400" alt="Screenshot"/>
+<img src="screenshots/3-save.png" height="400" alt="Screenshot"/>
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-Camera2Video
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2018 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/media/Camera2Video/kotlinApp/build.gradle b/media/Camera2Video/kotlinApp/build.gradle
new file mode 100644
index 0000000..60add8f
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/build.gradle
@@ -0,0 +1,22 @@
+buildscript {
+    ext.kotlin_version = '1.2.0'
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.0'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/media/Camera2Video/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/media/Camera2Video/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/media/Camera2Video/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..dda7c1f
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Dec 04 13:19:29 PST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/media/Camera2Video/kotlinApp/gradlew b/media/Camera2Video/kotlinApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/media/Camera2Video/kotlinApp/gradlew.bat b/media/Camera2Video/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/media/Camera2Video/kotlinApp/packaging.yaml b/media/Camera2Video/kotlinApp/packaging.yaml
new file mode 100644
index 0000000..26270dc
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status:       PUBLISHED
+technologies: [Android]
+categories:   [Media]
+languages:    [Java]
+solutions:    [Mobile]
+github:       googlesamples/android-Camera2Video
+level:        BEGINNER
+icon:         Camera2VideoSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license:      apache2
diff --git a/media/Camera2Video/kotlinApp/screenshots/1-launch.png b/media/Camera2Video/kotlinApp/screenshots/1-launch.png
new file mode 100644
index 0000000..24105bb
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/screenshots/1-launch.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/screenshots/2-record.png b/media/Camera2Video/kotlinApp/screenshots/2-record.png
new file mode 100644
index 0000000..bf79522
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/screenshots/2-record.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/screenshots/3-save.png b/media/Camera2Video/kotlinApp/screenshots/3-save.png
new file mode 100644
index 0000000..a070da4
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/screenshots/3-save.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/screenshots/icon-web.png b/media/Camera2Video/kotlinApp/screenshots/icon-web.png
new file mode 100644
index 0000000..a0a61c0
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/screenshots/icon-web.png
Binary files differ
diff --git a/media/Camera2Video/kotlinApp/settings.gradle b/media/Camera2Video/kotlinApp/settings.gradle
new file mode 100644
index 0000000..9464a35
--- /dev/null
+++ b/media/Camera2Video/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'Application'
diff --git a/media/HdrViewfinder/gradle/wrapper/gradle-wrapper.properties b/media/HdrViewfinder/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/media/HdrViewfinder/gradle/wrapper/gradle-wrapper.properties
+++ b/media/HdrViewfinder/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/MediaBrowserService/Application/build.gradle b/media/MediaBrowserService/Application/build.gradle
index 3621f95..c36e766 100644
--- a/media/MediaBrowserService/Application/build.gradle
+++ b/media/MediaBrowserService/Application/build.gradle
@@ -8,7 +8,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/media/MediaBrowserService/Application/src/main/AndroidManifest.xml b/media/MediaBrowserService/Application/src/main/AndroidManifest.xml
index 6af29f0..c947564 100644
--- a/media/MediaBrowserService/Application/src/main/AndroidManifest.xml
+++ b/media/MediaBrowserService/Application/src/main/AndroidManifest.xml
@@ -18,6 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.example.android.mediasession">
 
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
 
diff --git a/media/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties b/media/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties
index a93175f..a61334b 100644
--- a/media/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties
+++ b/media/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/media/MediaEffects/gradle/wrapper/gradle-wrapper.properties b/media/MediaEffects/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/media/MediaEffects/gradle/wrapper/gradle-wrapper.properties
+++ b/media/MediaEffects/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/MediaRecorder/gradle/wrapper/gradle-wrapper.properties b/media/MediaRecorder/gradle/wrapper/gradle-wrapper.properties
index 0010fe6..6befd5b 100644
--- a/media/MediaRecorder/gradle/wrapper/gradle-wrapper.properties
+++ b/media/MediaRecorder/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/MediaRouter/gradle/wrapper/gradle-wrapper.properties b/media/MediaRouter/gradle/wrapper/gradle-wrapper.properties
index 658084c..1b968aa 100644
--- a/media/MediaRouter/gradle/wrapper/gradle-wrapper.properties
+++ b/media/MediaRouter/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/MidiScope/gradle/wrapper/gradle-wrapper.properties b/media/MidiScope/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/media/MidiScope/gradle/wrapper/gradle-wrapper.properties
+++ b/media/MidiScope/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/MidiSynth/gradle/wrapper/gradle-wrapper.properties b/media/MidiSynth/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/media/MidiSynth/gradle/wrapper/gradle-wrapper.properties
+++ b/media/MidiSynth/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/media/PictureInPicture/app/build.gradle b/media/PictureInPicture/app/build.gradle
index 0c7760f..4ec0007 100644
--- a/media/PictureInPicture/app/build.gradle
+++ b/media/PictureInPicture/app/build.gradle
@@ -1,12 +1,11 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 26
-    buildToolsVersion "26.0.2"
+    compileSdkVersion 27
     defaultConfig {
         applicationId "com.example.android.pictureinpicture"
         minSdkVersion 26
-        targetSdkVersion 26
+        targetSdkVersion 27
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -24,8 +23,8 @@
     androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
         exclude group: 'com.android.support', module: 'support-annotations'
     })
-    compile 'com.android.support:appcompat-v7:26.1.0'
-    compile 'com.android.support:support-media-compat:26.1.0'
+    compile 'com.android.support:appcompat-v7:27.0.0'
+    compile 'com.android.support:support-media-compat:27.0.0'
 
     testCompile 'junit:junit:4.12'
 }
diff --git a/media/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.java b/media/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.java
index 90043f1..9398bf6 100644
--- a/media/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.java
+++ b/media/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.session.MediaControllerCompat;
 import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v4.media.session.PlaybackStateCompat;
@@ -137,6 +138,11 @@
         mSession.setActive(true);
         MediaControllerCompat.setMediaController(this, mSession.getController());
 
+        MediaMetadataCompat metadata = new MediaMetadataCompat.Builder()
+                .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, mMovieView.getTitle())
+                .build();
+        mSession.setMetadata(metadata);
+
         MediaSessionCallback mMediaSessionCallback = new MediaSessionCallback(mMovieView);
         mSession.setCallback(mMediaSessionCallback);
 
diff --git a/media/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.java b/media/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.java
index 0021a7b..6dd9177 100644
--- a/media/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.java
+++ b/media/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.java
@@ -85,6 +85,9 @@
     /** The resource ID for the video to play. */
     @RawRes private int mVideoResourceId;
 
+    /** The title of the video */
+    private String mTitle;
+
     /** Whether we adjust our view bounds or we fill the remaining area with black bars */
     private boolean mAdjustViewBounds;
 
@@ -117,16 +120,17 @@
         mFastRewind = findViewById(R.id.fast_rewind);
         mMinimize = findViewById(R.id.minimize);
 
-        // Attributes
-        final TypedArray a =
+        final TypedArray attributes =
                 context.obtainStyledAttributes(
                         attrs,
                         R.styleable.MovieView,
                         defStyleAttr,
                         R.style.Widget_PictureInPicture_MovieView);
-        setVideoResourceId(a.getResourceId(R.styleable.MovieView_android_src, 0));
-        setAdjustViewBounds(a.getBoolean(R.styleable.MovieView_android_adjustViewBounds, false));
-        a.recycle();
+        setVideoResourceId(attributes.getResourceId(R.styleable.MovieView_android_src, 0));
+        setAdjustViewBounds(
+                attributes.getBoolean(R.styleable.MovieView_android_adjustViewBounds, false));
+        setTitle(attributes.getString(R.styleable.MovieView_android_title));
+        attributes.recycle();
 
         // Bind view events
         final OnClickListener listener =
@@ -262,6 +266,24 @@
     }
 
     /**
+     * Sets the title of the video to play.
+     *
+     * @param title of the video.
+     */
+    public void setTitle(String title) {
+        this.mTitle = title;
+    }
+
+    /**
+     * The title of the video to play.
+     *
+     * @return title of the video.
+     */
+    public String getTitle() {
+        return mTitle;
+    }
+
+    /**
      * The raw resource id of the video to play.
      *
      * @return ID of the video resource.
diff --git a/media/PictureInPicture/app/src/main/res/layout/activity_main.xml b/media/PictureInPicture/app/src/main/res/layout/activity_main.xml
index 91487c8..ecd0b29 100644
--- a/media/PictureInPicture/app/src/main/res/layout/activity_main.xml
+++ b/media/PictureInPicture/app/src/main/res/layout/activity_main.xml
@@ -28,7 +28,8 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:adjustViewBounds="true"
-        android:src="@raw/vid_bigbuckbunny"/>
+        android:src="@raw/vid_bigbuckbunny"
+        android:title="@string/title_bigbuckbunny"/>
 
     <ScrollView
         android:id="@+id/scroll"
diff --git a/media/PictureInPicture/app/src/main/res/values/attrs.xml b/media/PictureInPicture/app/src/main/res/values/attrs.xml
index 482d621..27662a5 100644
--- a/media/PictureInPicture/app/src/main/res/values/attrs.xml
+++ b/media/PictureInPicture/app/src/main/res/values/attrs.xml
@@ -18,6 +18,7 @@
 
     <declare-styleable name="MovieView">
         <attr name="android:src"/>
+        <attr name="android:title"/>
         <attr name="android:adjustViewBounds"/>
     </declare-styleable>
 
diff --git a/media/PictureInPicture/app/src/main/res/values/strings.xml b/media/PictureInPicture/app/src/main/res/values/strings.xml
index 5bcafe2..f3fd428 100644
--- a/media/PictureInPicture/app/src/main/res/values/strings.xml
+++ b/media/PictureInPicture/app/src/main/res/values/strings.xml
@@ -33,4 +33,5 @@
     ]]></string>
     <string name="switch_custom">Switch to custom actions example</string>
     <string name="switch_media_session">Switch to using MediaSession</string>
+    <string name="title_bigbuckbunny">Big Buck Bunny</string>
 </resources>
diff --git a/media/PictureInPicture/build.gradle b/media/PictureInPicture/build.gradle
index 4ce13fc..58d61be 100644
--- a/media/PictureInPicture/build.gradle
+++ b/media/PictureInPicture/build.gradle
@@ -8,7 +8,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/media/PictureInPicture/gradle/wrapper/gradle-wrapper.properties b/media/PictureInPicture/gradle/wrapper/gradle-wrapper.properties
index 02e8c93..ee48ea2 100644
--- a/media/PictureInPicture/gradle/wrapper/gradle-wrapper.properties
+++ b/media/PictureInPicture/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/media/PictureInPicture/kotlinApp/app/build.gradle b/media/PictureInPicture/kotlinApp/app/build.gradle
index acb53a2..3a8a654 100644
--- a/media/PictureInPicture/kotlinApp/app/build.gradle
+++ b/media/PictureInPicture/kotlinApp/app/build.gradle
@@ -13,12 +13,11 @@
 apply plugin: 'kotlin-android-extensions'
 
 android {
-    compileSdkVersion 26
-    buildToolsVersion "26.0.2"
+    compileSdkVersion 27
     defaultConfig {
         applicationId "com.example.android.pictureinpicture"
         minSdkVersion 26
-        targetSdkVersion 26
+        targetSdkVersion 27
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -36,8 +35,8 @@
     androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
         exclude group: 'com.android.support', module: 'support-annotations'
     })
-    compile 'com.android.support:appcompat-v7:26.1.0'
-    compile 'com.android.support:support-media-compat:26.1.0'
+    compile 'com.android.support:appcompat-v7:27.0.0'
+    compile 'com.android.support:support-media-compat:27.0.0'
 
     testCompile 'junit:junit:4.12'
     compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
diff --git a/media/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.kt b/media/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.kt
index 0027501..962ff33 100644
--- a/media/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.kt
+++ b/media/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.kt
@@ -20,6 +20,7 @@
 import android.content.Intent
 import android.content.res.Configuration
 import android.os.Bundle
+import android.support.v4.media.MediaMetadataCompat
 import android.support.v4.media.session.MediaControllerCompat
 import android.support.v4.media.session.MediaSessionCompat
 import android.support.v4.media.session.PlaybackStateCompat
@@ -132,6 +133,11 @@
         mSession.isActive = true
         MediaControllerCompat.setMediaController(this, mSession.controller)
 
+        val metadata = MediaMetadataCompat.Builder()
+                .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, mMovieView.title)
+                .build()
+        mSession.setMetadata(metadata)
+
         val mMediaSessionCallback = MediaSessionCallback(mMovieView)
         mSession.setCallback(mMediaSessionCallback)
 
diff --git a/media/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.kt b/media/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.kt
index 5d85f69..59fc6d6 100644
--- a/media/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.kt
+++ b/media/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.kt
@@ -97,6 +97,8 @@
     @RawRes
     private var mVideoResourceId: Int = 0
 
+    var title: String = ""
+
     /** Whether we adjust our view bounds or we fill the remaining area with black bars  */
     private var mAdjustViewBounds: Boolean = false
 
@@ -125,6 +127,7 @@
                 defStyleAttr, R.style.Widget_PictureInPicture_MovieView)
         setVideoResourceId(a.getResourceId(R.styleable.MovieView_android_src, 0))
         setAdjustViewBounds(a.getBoolean(R.styleable.MovieView_android_adjustViewBounds, false))
+        title = a.getString(R.styleable.MovieView_android_title)
         a.recycle()
 
         // Bind view events
diff --git a/media/PictureInPicture/kotlinApp/app/src/main/res/layout/activity_main.xml b/media/PictureInPicture/kotlinApp/app/src/main/res/layout/activity_main.xml
index 91487c8..ecd0b29 100644
--- a/media/PictureInPicture/kotlinApp/app/src/main/res/layout/activity_main.xml
+++ b/media/PictureInPicture/kotlinApp/app/src/main/res/layout/activity_main.xml
@@ -28,7 +28,8 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:adjustViewBounds="true"
-        android:src="@raw/vid_bigbuckbunny"/>
+        android:src="@raw/vid_bigbuckbunny"
+        android:title="@string/title_bigbuckbunny"/>
 
     <ScrollView
         android:id="@+id/scroll"
diff --git a/media/PictureInPicture/kotlinApp/app/src/main/res/values/attrs.xml b/media/PictureInPicture/kotlinApp/app/src/main/res/values/attrs.xml
index 482d621..27662a5 100644
--- a/media/PictureInPicture/kotlinApp/app/src/main/res/values/attrs.xml
+++ b/media/PictureInPicture/kotlinApp/app/src/main/res/values/attrs.xml
@@ -18,6 +18,7 @@
 
     <declare-styleable name="MovieView">
         <attr name="android:src"/>
+        <attr name="android:title"/>
         <attr name="android:adjustViewBounds"/>
     </declare-styleable>
 
diff --git a/media/PictureInPicture/kotlinApp/app/src/main/res/values/strings.xml b/media/PictureInPicture/kotlinApp/app/src/main/res/values/strings.xml
index 5bcafe2..f3fd428 100644
--- a/media/PictureInPicture/kotlinApp/app/src/main/res/values/strings.xml
+++ b/media/PictureInPicture/kotlinApp/app/src/main/res/values/strings.xml
@@ -33,4 +33,5 @@
     ]]></string>
     <string name="switch_custom">Switch to custom actions example</string>
     <string name="switch_media_session">Switch to using MediaSession</string>
+    <string name="title_bigbuckbunny">Big Buck Bunny</string>
 </resources>
diff --git a/media/PictureInPicture/kotlinApp/build.gradle b/media/PictureInPicture/kotlinApp/build.gradle
index c8d330b..662789f 100644
--- a/media/PictureInPicture/kotlinApp/build.gradle
+++ b/media/PictureInPicture/kotlinApp/build.gradle
@@ -8,7 +8,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.0.0-beta7'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/media/PictureInPicture/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/media/PictureInPicture/kotlinApp/gradle/wrapper/gradle-wrapper.properties
index 8b227ef..6be2d8f 100644
--- a/media/PictureInPicture/kotlinApp/gradle/wrapper/gradle-wrapper.properties
+++ b/media/PictureInPicture/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/media/ScreenCapture/gradle/wrapper/gradle-wrapper.properties b/media/ScreenCapture/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/media/ScreenCapture/gradle/wrapper/gradle-wrapper.properties
+++ b/media/ScreenCapture/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/notification/ActiveNotifications/gradle/wrapper/gradle-wrapper.properties b/notification/ActiveNotifications/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/notification/ActiveNotifications/gradle/wrapper/gradle-wrapper.properties
+++ b/notification/ActiveNotifications/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/notification/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/notification/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/notification/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
+++ b/notification/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/notification/CustomNotifications/gradle/wrapper/gradle-wrapper.properties b/notification/CustomNotifications/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/notification/CustomNotifications/gradle/wrapper/gradle-wrapper.properties
+++ b/notification/CustomNotifications/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/notification/LNotifications/gradle/wrapper/gradle-wrapper.properties b/notification/LNotifications/gradle/wrapper/gradle-wrapper.properties
index 47a8bfd..5b7f974 100644
--- a/notification/LNotifications/gradle/wrapper/gradle-wrapper.properties
+++ b/notification/LNotifications/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/notification/MessagingService/gradle/wrapper/gradle-wrapper.properties b/notification/MessagingService/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/notification/MessagingService/gradle/wrapper/gradle-wrapper.properties
+++ b/notification/MessagingService/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/notification/NotificationChannels/gradle/wrapper/gradle-wrapper.properties b/notification/NotificationChannels/gradle/wrapper/gradle-wrapper.properties
index 846a696..b59b070 100644
--- a/notification/NotificationChannels/gradle/wrapper/gradle-wrapper.properties
+++ b/notification/NotificationChannels/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/notification/NotificationChannels/kotlinApp/Application/build.gradle b/notification/NotificationChannels/kotlinApp/Application/build.gradle
index 18f542d..0e38037 100644
--- a/notification/NotificationChannels/kotlinApp/Application/build.gradle
+++ b/notification/NotificationChannels/kotlinApp/Application/build.gradle
@@ -4,7 +4,7 @@
     }
     ext.kotlin_version = '1.1.2-4'
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.0'
+        classpath 'com.android.tools.build:gradle:3.0.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
diff --git a/notification/NotificationChannels/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/notification/NotificationChannels/kotlinApp/gradle/wrapper/gradle-wrapper.properties
index a5c7226..b59b070 100644
--- a/notification/NotificationChannels/kotlinApp/gradle/wrapper/gradle-wrapper.properties
+++ b/notification/NotificationChannels/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/renderScript/BasicRenderScript/gradle/wrapper/gradle-wrapper.properties b/renderScript/BasicRenderScript/gradle/wrapper/gradle-wrapper.properties
index ff55c68..3aae9a0 100644
--- a/renderScript/BasicRenderScript/gradle/wrapper/gradle-wrapper.properties
+++ b/renderScript/BasicRenderScript/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/renderScript/RenderScriptIntrinsic/gradle/wrapper/gradle-wrapper.properties b/renderScript/RenderScriptIntrinsic/gradle/wrapper/gradle-wrapper.properties
index da29496..d624516 100644
--- a/renderScript/RenderScriptIntrinsic/gradle/wrapper/gradle-wrapper.properties
+++ b/renderScript/RenderScriptIntrinsic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/security/AsymmetricFingerprintDialog/gradle/wrapper/gradle-wrapper.properties b/security/AsymmetricFingerprintDialog/gradle/wrapper/gradle-wrapper.properties
index 74d071f..8806b78 100644
--- a/security/AsymmetricFingerprintDialog/gradle/wrapper/gradle-wrapper.properties
+++ b/security/AsymmetricFingerprintDialog/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/security/ConfirmCredential/gradle/wrapper/gradle-wrapper.properties b/security/ConfirmCredential/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/security/ConfirmCredential/gradle/wrapper/gradle-wrapper.properties
+++ b/security/ConfirmCredential/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/security/DirectBoot/gradle/wrapper/gradle-wrapper.properties b/security/DirectBoot/gradle/wrapper/gradle-wrapper.properties
index 5b0e683..e62c525 100644
--- a/security/DirectBoot/gradle/wrapper/gradle-wrapper.properties
+++ b/security/DirectBoot/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/security/FingerprintDialog/Application/src/main/AndroidManifest.xml b/security/FingerprintDialog/Application/src/main/AndroidManifest.xml
index 337f641..218c190 100644
--- a/security/FingerprintDialog/Application/src/main/AndroidManifest.xml
+++ b/security/FingerprintDialog/Application/src/main/AndroidManifest.xml
@@ -31,7 +31,8 @@
 
         <activity
             android:name=".MainActivity"
-            android:label="@string/application_name">
+            android:label="@string/application_name"
+            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -40,6 +41,7 @@
 
         <activity
             android:name=".SettingsActivity"
-            android:label="@string/action_settings" />
+            android:label="@string/action_settings"
+            android:parentActivityName=".MainActivity"/>
     </application>
 </manifest>
diff --git a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/MainActivity.java b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/MainActivity.java
index 400b2d6..e30b4c2 100644
--- a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/MainActivity.java
+++ b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/MainActivity.java
@@ -16,7 +16,6 @@
 
 package com.example.android.fingerprintdialog;
 
-import android.app.Activity;
 import android.app.KeyguardManager;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -28,6 +27,8 @@
 import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.security.keystore.KeyProperties;
 import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
 import android.util.Base64;
 import android.util.Log;
 import android.view.Menu;
@@ -57,7 +58,7 @@
 /**
  * Main entry point for the sample, showing a backpack and "Purchase" button.
  */
-public class MainActivity extends Activity {
+public class MainActivity extends AppCompatActivity {
 
     private static final String TAG = MainActivity.class.getSimpleName();
 
@@ -74,6 +75,8 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
+        Toolbar toolbar = findViewById(R.id.toolbar);
+        setSupportActionBar(toolbar);
 
         try {
             mKeyStore = KeyStore.getInstance("AndroidKeyStore");
@@ -102,9 +105,8 @@
 
         KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
         FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
-        Button purchaseButton = (Button) findViewById(R.id.purchase_button);
-        Button purchaseButtonNotInvalidated = (Button) findViewById(
-                R.id.purchase_button_not_invalidated);
+        Button purchaseButton = findViewById(R.id.purchase_button);
+        Button purchaseButtonNotInvalidated = findViewById(R.id.purchase_button_not_invalidated);
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             purchaseButtonNotInvalidated.setEnabled(true);
@@ -115,8 +117,7 @@
             // Hide the purchase button which uses a non-invalidated key
             // if the app doesn't work on Android N preview
             purchaseButtonNotInvalidated.setVisibility(View.GONE);
-            findViewById(R.id.purchase_button_not_invalidated_description)
-                    .setVisibility(View.GONE);
+            findViewById(R.id.purchase_button_not_invalidated_description).setVisibility(View.GONE);
         }
 
         if (!keyguardManager.isKeyguardSecure()) {
@@ -138,7 +139,8 @@
             purchaseButton.setEnabled(false);
             // This happens when no fingerprints are registered.
             Toast.makeText(this,
-                    "Go to 'Settings -> Security -> Fingerprint' and register at least one fingerprint",
+                    "Go to 'Settings -> Security -> Fingerprint' and register at least one" +
+                            " fingerprint",
                     Toast.LENGTH_LONG).show();
             return;
         }
@@ -195,7 +197,7 @@
     private void showConfirmation(byte[] encrypted) {
         findViewById(R.id.confirmation_message).setVisibility(View.VISIBLE);
         if (encrypted != null) {
-            TextView v = (TextView) findViewById(R.id.encrypted_message);
+            TextView v = findViewById(R.id.encrypted_message);
             v.setVisibility(View.VISIBLE);
             v.setText(Base64.encodeToString(encrypted, 0 /* flags */));
         }
diff --git a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.java b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.java
index 08b3911..4ac8846 100644
--- a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.java
+++ b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.java
@@ -16,11 +16,11 @@
 
 package com.example.android.fingerprintdialog;
 
-import android.app.Activity;
 import android.os.Bundle;
 import android.preference.PreferenceFragment;
+import android.support.v7.app.AppCompatActivity;
 
-public class SettingsActivity extends Activity {
+public class SettingsActivity extends AppCompatActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/security/FingerprintDialog/Application/src/main/res/layout/activity_main.xml b/security/FingerprintDialog/Application/src/main/res/layout/activity_main.xml
index f0a596f..130bc8c 100644
--- a/security/FingerprintDialog/Application/src/main/res/layout/activity_main.xml
+++ b/security/FingerprintDialog/Application/src/main/res/layout/activity_main.xml
@@ -14,71 +14,80 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<ScrollView
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical">
+            android:layout_height="?attr/actionBarSize"
+            android:background="?attr/colorPrimary"
+            android:elevation="4dp"
+            android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
+            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
 
         <ImageView
-                android:layout_width="150dp"
-                android:layout_height="150dp"
-                android:layout_marginTop="32dp"
-                android:layout_marginBottom="32dp"
-                android:layout_gravity="center_horizontal"
-                android:scaleType="fitCenter"
-                android:src="@drawable/android_robot"
-                android:contentDescription="@string/description_bugdroid_icon"/>
+            android:layout_width="150dp"
+            android:layout_height="150dp"
+            android:layout_marginTop="32dp"
+            android:layout_marginBottom="32dp"
+            android:layout_gravity="center_horizontal"
+            android:scaleType="fitCenter"
+            android:src="@drawable/android_robot"
+            android:contentDescription="@string/description_bugdroid_icon"/>
 
         <LinearLayout
-                android:layout_width="match_parent"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginEnd="8dp"
+            android:orientation="vertical"
+            android:background="@drawable/card"
+            android:elevation="4dp"
+            android:paddingTop="16dp"
+            android:paddingBottom="16dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp">
+
+            <TextView
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginTop="8dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:orientation="vertical"
-                android:background="@drawable/card"
-                android:elevation="4dp"
-                android:paddingTop="16dp"
-                android:paddingBottom="16dp"
-                android:paddingStart="16dp"
-                android:paddingEnd="16dp">
+                android:textAppearance="@android:style/TextAppearance.Material.Headline"
+                android:text="@string/item_title"/>
 
             <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:textAppearance="@android:style/TextAppearance.Material.Headline"
-                    android:text="@string/item_title"/>
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="@android:style/TextAppearance.Material.Body2"
+                android:textColor="?android:attr/colorAccent"
+                android:text="@string/item_price"/>
 
             <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body2"
-                    android:textColor="?android:attr/colorAccent"
-                    android:text="@string/item_price"/>
-
-            <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_marginTop="16dp"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:text="@string/item_description"/>
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textColor="?android:attr/textColorSecondary"
+                android:text="@string/item_description"/>
 
         </LinearLayout>
         <Button style="@android:style/Widget.Material.Button.Colored"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="8dp"
-                android:layout_marginEnd="4dp"
-                android:layout_gravity="end"
-                android:textColor="?android:attr/textColorPrimaryInverse"
-                android:text="@string/purchase"
-                android:id="@+id/purchase_button" />
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:layout_marginEnd="4dp"
+            android:layout_gravity="end"
+            android:textColor="?android:attr/textColorPrimaryInverse"
+            android:text="@string/purchase"
+            android:id="@+id/purchase_button" />
 
         <Button style="@android:style/Widget.Material.Button.Colored"
             android:layout_width="wrap_content"
@@ -101,27 +110,27 @@
             />
 
         <TextView
-                android:id="@+id/confirmation_message"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="16dp"
-                android:paddingStart="16dp"
-                android:paddingEnd="16dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Body2"
-                android:textColor="?android:attr/colorAccent"
-                android:text="@string/purchase_done"
-                android:visibility="gone"/>
+            android:id="@+id/confirmation_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
+            android:textAppearance="@android:style/TextAppearance.Material.Body2"
+            android:textColor="?android:attr/colorAccent"
+            android:text="@string/purchase_done"
+            android:visibility="gone"/>
 
         <TextView
-                android:id="@+id/encrypted_message"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="16dp"
-                android:paddingStart="16dp"
-                android:paddingEnd="16dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Body2"
-                android:textColor="?android:attr/colorAccent"
-                android:text="@string/purchase_done"
-                android:visibility="gone"/>
+            android:id="@+id/encrypted_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
+            android:textAppearance="@android:style/TextAppearance.Material.Body2"
+            android:textColor="?android:attr/colorAccent"
+            android:text="@string/purchase_done"
+            android:visibility="gone"/>
     </LinearLayout>
 </ScrollView>
\ No newline at end of file
diff --git a/security/FingerprintDialog/gradle/wrapper/gradle-wrapper.properties b/security/FingerprintDialog/gradle/wrapper/gradle-wrapper.properties
index 6372a0a..3ed54ce 100644
--- a/security/FingerprintDialog/gradle/wrapper/gradle-wrapper.properties
+++ b/security/FingerprintDialog/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/security/FingerprintDialog/kotlinApp/.google/packaging.yaml b/security/FingerprintDialog/kotlinApp/.google/packaging.yaml
new file mode 100644
index 0000000..1846486
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/.google/packaging.yaml
@@ -0,0 +1,23 @@
+
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [security]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-FingerprintDialog
+level:        INTERMEDIATE
+icon:         screenshots/big-icon.png
+apiRefs:
+    - android:android.hardware.fingerprint.FingerprintManager
+    - android:android.hardware.fingerprint.FingerprintManager.AuthenticationCallback
+    - android:android.hardware.fingerprint.FingerprintManager.CryptoObject
+    - android:android.security.KeyGenParameterSpec
+    - android:java.security.KeyStore
+    - android:javax.crypto.Cipher
+    - android:javax.crypto.KeyGenerator
+license: apache2
diff --git a/security/FingerprintDialog/kotlinApp/README.md b/security/FingerprintDialog/kotlinApp/README.md
new file mode 100644
index 0000000..85650d0
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/README.md
@@ -0,0 +1,85 @@
+
+Android FingerprintDialog Sample (Kotlin)
+=========================================
+
+A sample that demonstrates to use registered fingerprints to authenticate the user in your app
+
+Introduction
+------------
+
+This sample demonstrates how you can use registered fingerprints in your app to authenticate the
+user before proceeding some actions such as purchasing an item.
+
+First you need to create a symmetric key in the Android Key Store using [KeyGenerator][1]
+which can be only be used after the user has authenticated with fingerprint and pass
+a [KeyGenParameterSpec][2].
+
+By setting [KeyGenParameterSpec.Builder.setUserAuthenticationRequired][3] to true, you can permit
+the use of the key only after the user authenticate it including when authenticated with the user's
+fingerprint.
+
+Then start listening to a fingerprint on the fingerprint sensor by calling
+[FingerprintManager.authenticate][4] with a [Cipher][5] initialized with the symmetric key created.
+Or alternatively you can fall back to server-side verified password as an authenticator.
+
+Once the fingerprint (or password) is verified, the
+[FingerprintManager.AuthenticationCallback#onAuthenticationSucceeded()][6] callback is called.
+
+[1]: https://developer.android.com/reference/javax/crypto/KeyGenerator.html
+[2]: https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.html
+[3]: https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.Builder.html#setUserAuthenticationRequired%28boolean%29
+[4]: https://developer.android.com/reference/android/hardware/fingerprint/FingerprintManager.html#authenticate%28android.hardware.fingerprint.FingerprintManager.CryptoObject,%20android.os.CancellationSignal,%20int,%20android.hardware.fingerprint.FingerprintManager.AuthenticationCallback,%20android.os.Handler%29
+[5]: https://developer.android.com/reference/javax/crypto/Cipher.html
+[6]: https://developer.android.com/reference/android/hardware/fingerprint/FingerprintManager.AuthenticationCallback.html#onAuthenticationSucceeded%28android.hardware.fingerprint.FingerprintManager.AuthenticationResult%29
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Support Repository
+
+Screenshots
+-------------
+
+<img src="screenshots/1-purchase-screen.png" height="400" alt="Screenshot"/>
+<img src="screenshots/2-fingerprint-dialog.png" height="400" alt="Screenshot"/>
+<img src="screenshots/3-fingerprint-authenticated.png" height="400" alt="Screenshot"/>
+<img src="screenshots/4-new-fingerprint-enrolled.png" height="400" alt="Screenshot"/>
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-FingerprintDialog
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2017 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/security/FingerprintDialog/kotlinApp/app/build.gradle b/security/FingerprintDialog/kotlinApp/app/build.gradle
new file mode 100644
index 0000000..58bfe13
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion 27
+    defaultConfig {
+        applicationId "com.example.android.fingerprintdialog"
+        minSdkVersion 24
+        targetSdkVersion 27
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:27.0.0"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+}
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/app/proguard-project.txt b/security/FingerprintDialog/kotlinApp/app/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# 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 *;
+#}
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/AndroidManifest.xml b/security/FingerprintDialog/kotlinApp/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9dffd1c
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<manifest package="com.example.android.fingerprintdialog"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/application_name"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.AppCompat.Light"
+        tools:ignore="GoogleAppIndexingWarning">
+
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/application_name"
+            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
+            android:name=".SettingsActivity"
+            android:label="@string/action_settings"
+            android:parentActivityName=".MainActivity"/>
+    </application>
+</manifest>
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/ActivityExtensions.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/ActivityExtensions.kt
new file mode 100644
index 0000000..108ca43
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/ActivityExtensions.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 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 com.example.android.fingerprintdialog
+
+import android.support.v7.app.AppCompatActivity
+import android.widget.Toast
+
+fun AppCompatActivity.showToast(text: String) {
+    Toast.makeText(this, text, Toast.LENGTH_LONG).show()
+}
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/Constants.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/Constants.kt
new file mode 100644
index 0000000..8f93fb1
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/Constants.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 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.
+ */
+
+@file:JvmName("Constants")
+
+package com.example.android.fingerprintdialog
+
+@JvmField val DEFAULT_KEY_NAME = "default_key"
+
+/**
+ * Enumeration to indicate which authentication method the user is trying to authenticate with.
+ */
+enum class Stage { FINGERPRINT, NEW_FINGERPRINT_ENROLLED, PASSWORD }
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.kt
new file mode 100644
index 0000000..f095e10
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.kt
@@ -0,0 +1,238 @@
+/*
+ * 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 com.example.android.fingerprintdialog
+
+import android.app.DialogFragment
+import android.content.Context
+import android.content.SharedPreferences
+import android.hardware.fingerprint.FingerprintManager
+import android.os.Bundle
+import android.preference.PreferenceManager
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.inputmethod.EditorInfo
+import android.view.inputmethod.InputMethodManager
+import android.widget.Button
+import android.widget.CheckBox
+import android.widget.EditText
+import android.widget.TextView
+
+/**
+ * A dialog which uses fingerprint APIs to authenticate the user, and falls back to password
+ * authentication if fingerprint is not available.
+ */
+class FingerprintAuthenticationDialogFragment : DialogFragment(),
+        TextView.OnEditorActionListener,
+        FingerprintUiHelper.Callback {
+
+    private lateinit var backupContent: View
+    private lateinit var cancelButton: Button
+    private lateinit var fingerprintContainer: View
+    private lateinit var fingerprintEnrolledTextView: TextView
+    private lateinit var passwordDescriptionTextView: TextView
+    private lateinit var passwordEditText: EditText
+    private lateinit var secondDialogButton: Button
+    private lateinit var useFingerprintFutureCheckBox: CheckBox
+
+    private lateinit var callback: Callback
+    private lateinit var cryptoObject: FingerprintManager.CryptoObject
+    private lateinit var fingerprintUiHelper: FingerprintUiHelper
+    private lateinit var inputMethodManager: InputMethodManager
+    private lateinit var sharedPreferences: SharedPreferences
+
+    private var stage = Stage.FINGERPRINT
+
+    private val showKeyboardRunnable = Runnable {
+        inputMethodManager.showSoftInput(passwordEditText, 0)
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        // Do not create a new Fragment when the Activity is re-created such as orientation changes.
+        retainInstance = true
+        setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog)
+    }
+
+    override fun onCreateView(inflater: LayoutInflater,
+            container: ViewGroup?,
+            savedInstanceState: Bundle?
+    ): View? {
+        dialog.setTitle(getString(R.string.sign_in))
+        return inflater.inflate(R.layout.fingerprint_dialog_container, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        backupContent = view.findViewById(R.id.backup_container)
+        cancelButton = view.findViewById(R.id.cancel_button)
+        fingerprintContainer = view.findViewById(R.id.fingerprint_container)
+        fingerprintEnrolledTextView = view.findViewById(R.id.new_fingerprint_enrolled_description)
+        passwordDescriptionTextView = view.findViewById(R.id.password_description)
+        passwordEditText = view.findViewById(R.id.password)
+        secondDialogButton = view.findViewById(R.id.second_dialog_button)
+        useFingerprintFutureCheckBox = view.findViewById(R.id.use_fingerprint_in_future_check)
+
+        cancelButton.setOnClickListener { dismiss() }
+        passwordEditText.setOnEditorActionListener(this)
+        secondDialogButton.setOnClickListener {
+            if (stage == Stage.FINGERPRINT) goToBackup() else verifyPassword()
+        }
+
+        fingerprintUiHelper = FingerprintUiHelper(
+                activity.getSystemService(FingerprintManager::class.java),
+                view.findViewById(R.id.fingerprint_icon),
+                view.findViewById(R.id.fingerprint_status),
+                this
+        )
+        updateStage()
+
+        // If fingerprint authentication is not available, switch immediately to the backup
+        // (password) screen.
+        if (!fingerprintUiHelper.isFingerprintAuthAvailable) {
+            goToBackup()
+        }
+    }
+    override fun onResume() {
+        super.onResume()
+        if (stage == Stage.FINGERPRINT) {
+            fingerprintUiHelper.startListening(cryptoObject)
+        }
+    }
+
+    override fun onPause() {
+        super.onPause()
+        fingerprintUiHelper.stopListening()
+    }
+
+    override fun onAttach(context: Context) {
+        super.onAttach(context)
+        inputMethodManager = context.getSystemService(InputMethodManager::class.java)
+        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
+    }
+
+    fun setCallback(callback: Callback) {
+        this.callback = callback
+    }
+
+    fun setCryptoObject(cryptoObject: FingerprintManager.CryptoObject) {
+        this.cryptoObject = cryptoObject
+    }
+
+    fun setStage(stage: Stage) {
+        this.stage = stage
+    }
+
+    /**
+     * Switches to backup (password) screen. This either can happen when fingerprint is not
+     * available or the user chooses to use the password authentication method by pressing the
+     * button. This can also happen when the user has too many invalid fingerprint attempts.
+     */
+    private fun goToBackup() {
+        stage = Stage.PASSWORD
+        updateStage()
+        passwordEditText.run {
+            requestFocus()
+
+            // Show the keyboard.
+            postDelayed(showKeyboardRunnable, 500)
+        }
+
+        // Fingerprint is not used anymore. Stop listening for it.
+        fingerprintUiHelper.stopListening()
+    }
+
+    /**
+     * Checks whether the current entered password is correct, and dismisses the dialog and
+     * informs the activity about the result.
+     */
+    private fun verifyPassword() {
+        if (!checkPassword(passwordEditText.text.toString())) {
+            return
+        }
+        if (stage == Stage.NEW_FINGERPRINT_ENROLLED) {
+            sharedPreferences.edit()
+                    .putBoolean(getString(R.string.use_fingerprint_to_authenticate_key),
+                            useFingerprintFutureCheckBox.isChecked)
+                    .apply()
+
+            if (useFingerprintFutureCheckBox.isChecked) {
+                // Re-create the key so that fingerprints including new ones are validated.
+                callback.createKey(DEFAULT_KEY_NAME)
+                stage = Stage.FINGERPRINT
+            }
+        }
+        passwordEditText.setText("")
+        callback.onPurchased(withFingerprint = false)
+        dismiss()
+    }
+
+    /**
+     * Checks if the given password is valid. Assume that the password is always correct.
+     * In a real world situation, the password needs to be verified via the server.
+     *
+     * @param password The password String
+     *
+     * @return true if `password` is correct, false otherwise
+     */
+    private fun checkPassword(password: String) = password.isNotEmpty()
+
+    private fun updateStage() {
+        when (stage) {
+            Stage.FINGERPRINT -> {
+                cancelButton.setText(R.string.cancel)
+                secondDialogButton.setText(R.string.use_password)
+                fingerprintContainer.visibility = View.VISIBLE
+                backupContent.visibility = View.GONE
+            }
+            Stage.NEW_FINGERPRINT_ENROLLED, // Intentional fall through
+            Stage.PASSWORD -> {
+                cancelButton.setText(R.string.cancel)
+                secondDialogButton.setText(R.string.ok)
+                fingerprintContainer.visibility = View.GONE
+                backupContent.visibility = View.VISIBLE
+                if (stage == Stage.NEW_FINGERPRINT_ENROLLED) {
+                    passwordDescriptionTextView.visibility = View.GONE
+                    fingerprintEnrolledTextView.visibility = View.VISIBLE
+                    useFingerprintFutureCheckBox.visibility = View.VISIBLE
+                }
+            }
+        }
+    }
+
+    override fun onEditorAction(v: TextView, actionId: Int, event: KeyEvent?): Boolean {
+        return if (actionId == EditorInfo.IME_ACTION_GO) { verifyPassword(); true } else false
+    }
+
+    override fun onAuthenticated() {
+        // Callback from FingerprintUiHelper. Let the activity know that authentication succeeded.
+        callback.onPurchased(withFingerprint = true, crypto = cryptoObject)
+        dismiss()
+    }
+
+    override fun onError() {
+        goToBackup()
+    }
+
+    interface Callback {
+        fun onPurchased(withFingerprint: Boolean, crypto: FingerprintManager.CryptoObject? = null)
+        fun createKey(keyName: String, invalidatedByBiometricEnrollment: Boolean = true)
+    }
+}
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.kt
new file mode 100644
index 0000000..ad38abc
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.kt
@@ -0,0 +1,112 @@
+/*
+ * 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 com.example.android.fingerprintdialog
+
+import android.hardware.fingerprint.FingerprintManager
+import android.os.CancellationSignal
+import android.widget.ImageView
+import android.widget.TextView
+
+/**
+ * Small helper class to manage text/icon around fingerprint authentication UI.
+ */
+class FingerprintUiHelper
+
+/**
+ * Constructor for [FingerprintUiHelper].
+ */
+internal constructor(private val fingerprintMgr: FingerprintManager,
+        private val icon: ImageView,
+        private val errorTextView: TextView,
+        private val callback: Callback
+) : FingerprintManager.AuthenticationCallback() {
+
+    private var cancellationSignal: CancellationSignal? = null
+    private var selfCancelled = false
+
+    val isFingerprintAuthAvailable: Boolean
+        get() = fingerprintMgr.isHardwareDetected && fingerprintMgr.hasEnrolledFingerprints()
+
+    private val resetErrorTextRunnable = Runnable {
+        icon.setImageResource(R.drawable.ic_fp_40px)
+        errorTextView.run {
+            setTextColor(errorTextView.resources.getColor(R.color.hint_color, null))
+            text = errorTextView.resources.getString(R.string.fingerprint_hint)
+        }
+    }
+
+    fun startListening(cryptoObject: FingerprintManager.CryptoObject) {
+        if (!isFingerprintAuthAvailable) return
+        cancellationSignal = CancellationSignal()
+        selfCancelled = false
+        fingerprintMgr.authenticate(cryptoObject, cancellationSignal, 0, this, null)
+        icon.setImageResource(R.drawable.ic_fp_40px)
+    }
+
+    fun stopListening() {
+        cancellationSignal?.also {
+            selfCancelled = true
+            it.cancel()
+        }
+        cancellationSignal = null
+    }
+
+    override fun onAuthenticationError(errMsgId: Int, errString: CharSequence) {
+        if (!selfCancelled) {
+            showError(errString)
+            icon.postDelayed({ callback.onError() }, ERROR_TIMEOUT_MILLIS)
+        }
+    }
+
+    override fun onAuthenticationHelp(helpMsgId: Int, helpString: CharSequence) =
+            showError(helpString)
+
+    override fun onAuthenticationFailed() =
+            showError(icon.resources.getString(R.string.fingerprint_not_recognized))
+
+    override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
+        errorTextView.run {
+            removeCallbacks(resetErrorTextRunnable)
+            setTextColor(errorTextView.resources.getColor(R.color.success_color, null))
+            text = errorTextView.resources.getString(R.string.fingerprint_success)
+        }
+        icon.run {
+            setImageResource(R.drawable.ic_fingerprint_success)
+            postDelayed({ callback.onAuthenticated() }, SUCCESS_DELAY_MILLIS)
+        }
+    }
+
+    private fun showError(error: CharSequence) {
+        icon.setImageResource(R.drawable.ic_fingerprint_error)
+        errorTextView.run {
+            text = error
+            setTextColor(errorTextView.resources.getColor(R.color.warning_color, null))
+            removeCallbacks(resetErrorTextRunnable)
+            postDelayed(resetErrorTextRunnable, ERROR_TIMEOUT_MILLIS)
+        }
+    }
+
+    interface Callback {
+        fun onAuthenticated()
+        fun onError()
+    }
+
+    companion object {
+        val ERROR_TIMEOUT_MILLIS: Long = 1600
+        val SUCCESS_DELAY_MILLIS: Long = 1300
+    }
+}
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/MainActivity.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/MainActivity.kt
new file mode 100644
index 0000000..0a4732d
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/MainActivity.kt
@@ -0,0 +1,332 @@
+/*
+ * 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 com.example.android.fingerprintdialog
+
+import android.app.KeyguardManager
+import android.content.Intent
+import android.content.SharedPreferences
+import android.hardware.fingerprint.FingerprintManager
+import android.os.Bundle
+import android.preference.PreferenceManager
+import android.security.keystore.KeyGenParameterSpec
+import android.security.keystore.KeyPermanentlyInvalidatedException
+import android.security.keystore.KeyProperties
+import android.security.keystore.KeyProperties.BLOCK_MODE_CBC
+import android.security.keystore.KeyProperties.ENCRYPTION_PADDING_PKCS7
+import android.security.keystore.KeyProperties.KEY_ALGORITHM_AES
+import android.support.v7.app.AppCompatActivity
+import android.util.Base64
+import android.util.Log
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.widget.Button
+import android.widget.TextView
+import android.widget.Toast
+import java.io.IOException
+import java.security.InvalidAlgorithmParameterException
+import java.security.InvalidKeyException
+import java.security.KeyStore
+import java.security.KeyStoreException
+import java.security.NoSuchAlgorithmException
+import java.security.NoSuchProviderException
+import java.security.UnrecoverableKeyException
+import java.security.cert.CertificateException
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.KeyGenerator
+import javax.crypto.NoSuchPaddingException
+import javax.crypto.SecretKey
+
+/**
+ * Main entry point for the sample, showing a backpack and "Purchase" button.
+ */
+class MainActivity : AppCompatActivity(),
+    FingerprintAuthenticationDialogFragment.Callback {
+
+    private lateinit var keyStore: KeyStore
+    private lateinit var keyGenerator: KeyGenerator
+    private lateinit var sharedPreferences: SharedPreferences
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+        setSupportActionBar(findViewById(R.id.toolbar))
+        setupKeyStoreAndKeyGenerator()
+
+        val (defaultCipher: Cipher, cipherNotInvalidated: Cipher) = setupCiphers()
+        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
+        setUpPurchaseButtons(cipherNotInvalidated, defaultCipher)
+    }
+
+    /**
+     * Enables or disables purchase buttons and sets the appropriate click listeners.
+     *
+     * @param cipherNotInvalidated cipher for the not invalidated purchase button
+     * @param defaultCipher the default cipher, used for the purchase button
+     */
+    private fun setUpPurchaseButtons(cipherNotInvalidated: Cipher, defaultCipher: Cipher) {
+        val purchaseButton = findViewById<Button>(R.id.purchase_button)
+        val purchaseButtonNotInvalidated =
+                findViewById<Button>(R.id.purchase_button_not_invalidated)
+
+        purchaseButtonNotInvalidated.run {
+            isEnabled = true
+            setOnClickListener(PurchaseButtonClickListener(
+                    cipherNotInvalidated, KEY_NAME_NOT_INVALIDATED))
+        }
+
+        val keyguardManager = getSystemService(KeyguardManager::class.java)
+        if (!keyguardManager.isKeyguardSecure) {
+            // Show a message that the user hasn't set up a fingerprint or lock screen.
+            showToast(getString(R.string.setup_lock_screen))
+            purchaseButton.isEnabled = false
+            purchaseButtonNotInvalidated.isEnabled = false
+            return
+        }
+
+        val fingerprintManager = getSystemService(FingerprintManager::class.java)
+        if (!fingerprintManager.hasEnrolledFingerprints()) {
+            purchaseButton.isEnabled = false
+            // This happens when no fingerprints are registered.
+            showToast(getString(R.string.register_fingerprint))
+            return
+        }
+
+        createKey(DEFAULT_KEY_NAME)
+        createKey(KEY_NAME_NOT_INVALIDATED, false)
+        purchaseButton.run {
+            isEnabled = true
+            setOnClickListener(PurchaseButtonClickListener(defaultCipher, DEFAULT_KEY_NAME))
+        }
+    }
+
+    /**
+     * Sets up KeyStore and KeyGenerator
+     */
+    private fun setupKeyStoreAndKeyGenerator() {
+        try {
+            keyStore = KeyStore.getInstance(ANDROID_KEY_STORE)
+        } catch (e: KeyStoreException) {
+            throw RuntimeException("Failed to get an instance of KeyStore", e)
+        }
+
+        try {
+            keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM_AES, ANDROID_KEY_STORE)
+        } catch (e: Exception) {
+            when (e) {
+                is NoSuchAlgorithmException,
+                is NoSuchProviderException ->
+                    throw RuntimeException("Failed to get an instance of KeyGenerator", e)
+                else -> throw e
+            }
+        }
+    }
+
+    /**
+     * Sets up default cipher and a non-invalidated cipher
+     */
+    private fun setupCiphers(): Pair<Cipher, Cipher> {
+        val defaultCipher: Cipher
+        val cipherNotInvalidated: Cipher
+        try {
+            val cipherString = "$KEY_ALGORITHM_AES/$BLOCK_MODE_CBC/$ENCRYPTION_PADDING_PKCS7"
+            defaultCipher = Cipher.getInstance(cipherString)
+            cipherNotInvalidated = Cipher.getInstance(cipherString)
+        } catch (e: Exception) {
+            when (e) {
+                is NoSuchAlgorithmException,
+                is NoSuchPaddingException ->
+                    throw RuntimeException("Failed to get an instance of Cipher", e)
+                else -> throw e
+            }
+        }
+        return Pair(defaultCipher, cipherNotInvalidated)
+    }
+
+    /**
+     * Initialize the [Cipher] instance with the created key in the [createKey] method.
+     *
+     * @param keyName the key name to init the cipher
+     * @return `true` if initialization succeeded, `false` if the lock screen has been disabled or
+     * reset after key generation, or if a fingerprint was enrolled after key generation.
+     */
+    private fun initCipher(cipher: Cipher, keyName: String): Boolean {
+        try {
+            keyStore.load(null)
+            cipher.init(Cipher.ENCRYPT_MODE, keyStore.getKey(keyName, null) as SecretKey)
+            return true
+        } catch (e: Exception) {
+            when (e) {
+                is KeyPermanentlyInvalidatedException -> return false
+                is KeyStoreException,
+                is CertificateException,
+                is UnrecoverableKeyException,
+                is IOException,
+                is NoSuchAlgorithmException,
+                is InvalidKeyException -> throw RuntimeException("Failed to init Cipher", e)
+                else -> throw e
+            }
+        }
+    }
+
+    /**
+     * Proceed with the purchase operation
+     *
+     * @param withFingerprint `true` if the purchase was made by using a fingerprint
+     * @param crypto the Crypto object
+     */
+    override fun onPurchased(withFingerprint: Boolean, crypto: FingerprintManager.CryptoObject?) {
+        if (withFingerprint) {
+            // If the user authenticated with fingerprint, verify using cryptography and then show
+            // the confirmation message.
+            if (crypto != null) {
+                tryEncrypt(crypto.cipher)
+            }
+        } else {
+            // Authentication happened with backup password. Just show the confirmation message.
+            showConfirmation()
+        }
+    }
+
+    // Show confirmation message. Also show crypto information if fingerprint was used.
+    private fun showConfirmation(encrypted: ByteArray? = null) {
+        findViewById<View>(R.id.confirmation_message).visibility = View.VISIBLE
+        if (encrypted != null) {
+            findViewById<TextView>(R.id.encrypted_message).run {
+                visibility = View.VISIBLE
+                text = Base64.encodeToString(encrypted, 0 /* flags */)
+            }
+        }
+    }
+
+    /**
+     * Tries to encrypt some data with the generated key from [createKey]. This only works if the
+     * user just authenticated via fingerprint.
+     */
+    private fun tryEncrypt(cipher: Cipher) {
+        try {
+            showConfirmation(cipher.doFinal(SECRET_MESSAGE.toByteArray()))
+        } catch (e: Exception) {
+            when (e) {
+                is BadPaddingException,
+                is IllegalBlockSizeException -> {
+                    Toast.makeText(this, "Failed to encrypt the data with the generated key. "
+                            + "Retry the purchase", Toast.LENGTH_LONG).show()
+                    Log.e(TAG, "Failed to encrypt the data with the generated key. ${e.message}")
+                }
+                else -> throw e
+            }
+        }
+    }
+
+    /**
+     * Creates a symmetric key in the Android Key Store which can only be used after the user has
+     * authenticated with a fingerprint.
+     *
+     * @param keyName the name of the key to be created
+     * @param invalidatedByBiometricEnrollment if `false` is passed, the created key will not be
+     * invalidated even if a new fingerprint is enrolled. The default value is `true` - the key will
+     * be invalidated if a new fingerprint is enrolled.
+     */
+    override fun createKey(keyName: String, invalidatedByBiometricEnrollment: Boolean) {
+        // The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint
+        // for your flow. Use of keys is necessary if you need to know if the set of enrolled
+        // fingerprints has changed.
+        try {
+            keyStore.load(null)
+
+            val keyProperties = KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
+            val builder = KeyGenParameterSpec.Builder(keyName, keyProperties)
+                    .setBlockModes(BLOCK_MODE_CBC)
+                    .setUserAuthenticationRequired(true)
+                    .setEncryptionPaddings(ENCRYPTION_PADDING_PKCS7)
+                    .setInvalidatedByBiometricEnrollment(invalidatedByBiometricEnrollment)
+
+            keyGenerator.run {
+                init(builder.build())
+                generateKey()
+            }
+        } catch (e: Exception) {
+            when (e) {
+                is NoSuchAlgorithmException,
+                is InvalidAlgorithmParameterException,
+                is CertificateException,
+                is IOException -> throw RuntimeException(e)
+                else -> throw e
+            }
+        }
+    }
+
+    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+        menuInflater.inflate(R.menu.menu_main, menu)
+        return true
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        if (item.itemId == R.id.action_settings) {
+            val intent = Intent(this, SettingsActivity::class.java)
+            startActivity(intent)
+            return true
+        }
+        return super.onOptionsItemSelected(item)
+    }
+
+    private inner class PurchaseButtonClickListener internal constructor(
+            internal var cipher: Cipher,
+            internal var keyName: String
+    ) : View.OnClickListener {
+
+        override fun onClick(view: View) {
+            findViewById<View>(R.id.confirmation_message).visibility = View.GONE
+            findViewById<View>(R.id.encrypted_message).visibility = View.GONE
+
+            val fragment = FingerprintAuthenticationDialogFragment()
+            fragment.setCryptoObject(FingerprintManager.CryptoObject(cipher))
+            fragment.setCallback(this@MainActivity)
+
+            // Set up the crypto object for later, which will be authenticated by fingerprint usage.
+            if (initCipher(cipher, keyName)) {
+
+                // Show the fingerprint dialog. The user has the option to use the fingerprint with
+                // crypto, or can fall back to using a server-side verified password.
+                val useFingerprintPreference = sharedPreferences
+                        .getBoolean(getString(R.string.use_fingerprint_to_authenticate_key), true)
+                if (useFingerprintPreference) {
+                    fragment.setStage(Stage.FINGERPRINT)
+                } else {
+                    fragment.setStage(Stage.PASSWORD)
+                }
+            } else {
+                // This happens if the lock screen has been disabled or or a fingerprint was
+                // enrolled. Thus, show the dialog to authenticate with their password first and ask
+                // the user if they want to authenticate with a fingerprint in the future.
+                fragment.setStage(Stage.NEW_FINGERPRINT_ENROLLED)
+            }
+            fragment.show(fragmentManager, DIALOG_FRAGMENT_TAG)
+        }
+    }
+
+    companion object {
+        private val ANDROID_KEY_STORE = "AndroidKeyStore"
+        private val DIALOG_FRAGMENT_TAG = "myFragment"
+        private val KEY_NAME_NOT_INVALIDATED = "key_not_invalidated"
+        private val SECRET_MESSAGE = "Very secret message"
+        private val TAG = MainActivity::class.java.simpleName
+    }
+}
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.kt
new file mode 100644
index 0000000..6a8dc16
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.kt
@@ -0,0 +1,31 @@
+/*
+ * 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 com.example.android.fingerprintdialog
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+
+class SettingsActivity : AppCompatActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        fragmentManager.beginTransaction()
+                .replace(android.R.id.content, SettingsFragment())
+                .commit()
+    }
+
+}
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsFragment.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsFragment.kt
new file mode 100644
index 0000000..0681e6d
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsFragment.kt
@@ -0,0 +1,29 @@
+/*
+ * 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 com.example.android.fingerprintdialog
+
+import android.os.Bundle
+import android.preference.PreferenceFragment
+
+class SettingsFragment : PreferenceFragment() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        addPreferencesFromResource(R.xml.preferences)
+    }
+
+}
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-hdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-hdpi/ic_fp_40px.png
new file mode 100644
index 0000000..48ebd8a
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-hdpi/ic_fp_40px.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-mdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-mdpi/ic_fp_40px.png
new file mode 100644
index 0000000..122f442
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-mdpi/ic_fp_40px.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-nodpi/android_robot.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-nodpi/android_robot.png
new file mode 100644
index 0000000..40bf934
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-nodpi/android_robot.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xhdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xhdpi/ic_fp_40px.png
new file mode 100644
index 0000000..e1c9590
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xhdpi/ic_fp_40px.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png
new file mode 100644
index 0000000..f7e8724
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png
new file mode 100644
index 0000000..0fb8545
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/card.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/card.xml
new file mode 100644
index 0000000..cdd2907
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/card.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <solid
+        android:color="@color/card_solid"/>
+
+    <corners
+        android:radius="@dimen/card_corner" />
+</shape>
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_error.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_error.xml
new file mode 100644
index 0000000..b382543
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_error.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="@dimen/fingerprint_square_dimen"
+        android:height="@dimen/fingerprint_square_dimen"
+        android:viewportWidth="@dimen/fingerprint_square_dimen_viewport"
+        android:viewportHeight="@dimen/fingerprint_square_dimen_viewport">
+    <path
+        android:pathData="M20.0,0.0C8.96,0.0 0.0,8.95 0.0,20.0s8.96,20.0 20.0,20.0c11.04,0.0 20.0,-8.95 20.0,-20.0S31.04,0.0 20.0,0.0z"
+        android:fillColor="@color/finerprint_error"/>
+    <path
+        android:pathData="M21.33,29.33l-2.67,0.0l0.0,-2.67l2.67,0.0L21.33,29.33zM21.33,22.67l-2.67,0.0l0.0,-12.0l2.67,0.0L21.33,22.67z"
+        android:fillColor="@color/fingerprint_fill"/>
+</vector>
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_success.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_success.xml
new file mode 100644
index 0000000..0195cd7
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_success.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="@dimen/fingerprint_square_dimen"
+        android:height="@dimen/fingerprint_square_dimen"
+        android:viewportWidth="@dimen/fingerprint_square_dimen_viewport"
+        android:viewportHeight="@dimen/fingerprint_square_dimen_viewport">
+    <path
+        android:pathData="M20.0,20.0m-20.0,0.0a20.0,20.0 0.0,1.0 1.0,40.0 0.0a20.0,20.0 0.0,1.0 1.0,-40.0 0.0"
+        android:fillColor="@color/fingerprint_success"/>
+    <path
+        android:pathData="M11.2,21.41l1.63,-1.619999 4.17,4.169998 10.59,-10.589999 1.619999,1.63 -12.209999,12.209999z"
+        android:fillColor="@color/fingerprint_fill"/>
+</vector>
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/activity_main.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..fedfde6
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?attr/actionBarSize"
+            android:background="?attr/colorPrimary"
+            android:elevation="@dimen/default_elevation"
+            android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
+            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
+
+        <ImageView
+            android:layout_width="@dimen/logo_square_dimen"
+            android:layout_height="@dimen/logo_square_dimen"
+            android:layout_marginTop="@dimen/logo_square_margin"
+            android:layout_marginBottom="@dimen/logo_square_margin"
+            android:layout_gravity="center_horizontal"
+            android:scaleType="fitCenter"
+            android:src="@drawable/android_robot"
+            android:contentDescription="@string/description_bugdroid_icon"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/default_margin_small"
+            android:layout_marginStart="@dimen/default_margin_small"
+            android:layout_marginEnd="@dimen/default_margin_small"
+            android:orientation="vertical"
+            android:background="@drawable/card"
+            android:elevation="@dimen/default_elevation"
+            android:paddingTop="@dimen/default_padding"
+            android:paddingBottom="@dimen/default_padding"
+            android:paddingStart="@dimen/default_padding"
+            android:paddingEnd="@dimen/default_padding">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="@android:style/TextAppearance.Material.Headline"
+                android:text="@string/item_title"/>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="@android:style/TextAppearance.Material.Body2"
+                android:textColor="?android:attr/colorAccent"
+                android:text="@string/item_price"/>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/default_margin"
+                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textColor="?android:attr/textColorSecondary"
+                android:text="@string/item_description"/>
+
+        </LinearLayout>
+
+        <Button style="@android:style/Widget.Material.Button.Colored"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/default_margin_small"
+            android:layout_marginEnd="@dimen/default_margin_end"
+            android:layout_gravity="end"
+            android:textColor="?android:attr/textColorPrimaryInverse"
+            android:text="@string/purchase"
+            android:id="@+id/purchase_button" />
+
+        <Button style="@android:style/Widget.Material.Button.Colored"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/default_margin_small"
+            android:layout_marginEnd="@dimen/default_margin_end"
+            android:layout_gravity="end"
+            android:textColor="?android:attr/textColorPrimaryInverse"
+            android:text="@string/purchase_not_invalidated"
+            android:id="@+id/purchase_button_not_invalidated" />
+
+        <TextView
+            android:id="@+id/purchase_button_not_invalidated_description"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/default_margin_end"
+            android:gravity="end"
+            android:textAlignment="gravity"
+            android:text="@string/purchase_button_not_invalidated_description"/>
+
+        <TextView
+            android:id="@+id/confirmation_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/default_margin"
+            android:paddingStart="@dimen/default_padding"
+            android:paddingEnd="@dimen/default_padding"
+            android:textAppearance="@android:style/TextAppearance.Material.Body2"
+            android:textColor="?android:attr/colorAccent"
+            android:text="@string/purchase_done"
+            android:visibility="gone"/>
+
+        <TextView
+            android:id="@+id/encrypted_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/default_margin"
+            android:paddingStart="@dimen/default_padding"
+            android:paddingEnd="@dimen/default_padding"
+            android:textAppearance="@android:style/TextAppearance.Material.Body2"
+            android:textColor="?android:attr/colorAccent"
+            android:text="@string/purchase_done"
+            android:visibility="gone"/>
+
+    </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_backup.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_backup.xml
new file mode 100644
index 0000000..9668f50
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_backup.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/backup_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="@dimen/default_padding"
+    android:paddingBottom="@dimen/default_padding_small">
+
+    <FrameLayout
+        android:id="@+id/description"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentStart="true"
+        android:layout_marginStart="@dimen/fingerprint_margin"
+        android:layout_marginEnd="@dimen/fingerprint_margin">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+            android:text="@string/password_description"
+            android:id="@+id/password_description"
+            android:textColor="?android:attr/textColorSecondary" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+            android:text="@string/new_fingerprint_enrolled_description"
+            android:id="@+id/new_fingerprint_enrolled_description"
+            android:visibility="gone"
+            android:textColor="?android:attr/textColorSecondary" />
+    </FrameLayout>
+
+    <EditText
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:inputType="textPassword"
+        android:ems="10"
+        android:hint="@string/password"
+        android:imeOptions="actionGo"
+        android:id="@+id/password"
+        android:layout_below="@+id/description"
+        android:layout_marginTop="@dimen/fingerprint_margin_vertical"
+        android:layout_marginStart="@dimen/fingerprint_margin_horizontal"
+        android:layout_marginEnd="@dimen/fingerprint_margin_horizontal"
+        android:layout_alignParentStart="true" />
+
+    <CheckBox
+        android:id="@+id/use_fingerprint_in_future_check"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/password"
+        android:layout_alignParentStart="true"
+        android:layout_marginTop="@dimen/fingerprint_margin_vertical"
+        android:layout_marginStart="@dimen/fingerprint_margin_horizontal"
+        android:layout_marginEnd="@dimen/fingerprint_margin_horizontal"
+        android:checked="true"
+        android:visibility="gone"
+        android:text="@string/use_fingerprint_in_future" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_container.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_container.xml
new file mode 100644
index 0000000..c5881ff
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_container.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<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:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <include layout="@layout/fingerprint_dialog_content" />
+
+        <include
+            layout="@layout/fingerprint_dialog_backup"
+            android:visibility="gone" />
+
+    </FrameLayout>
+
+    <LinearLayout
+        android:id="@+id/buttonPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingStart="@dimen/fingerprint_padding_horizontal"
+        android:paddingEnd="@dimen/fingerprint_padding_horizontal"
+        android:paddingTop="@dimen/fingerprint_padding_vertical"
+        android:paddingBottom="@dimen/fingerprint_padding_vertical"
+        android:gravity="bottom"
+        style="?android:attr/buttonBarStyle">
+
+        <Space
+            android:id="@+id/spacer"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:visibility="invisible" />
+        <Button
+            android:id="@+id/cancel_button"
+            style="?android:attr/buttonBarNegativeButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+        <Button
+            android:id="@+id/second_dialog_button"
+            style="?android:attr/buttonBarPositiveButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_content.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_content.xml
new file mode 100644
index 0000000..c68a178
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_content.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/fingerprint_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/default_padding_small"
+    android:paddingStart="@dimen/default_padding_large"
+    android:paddingEnd="@dimen/default_padding_large"
+    android:paddingTop="@dimen/default_padding">
+
+    <TextView
+        android:id="@+id/fingerprint_description"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true"
+        android:text="@string/fingerprint_description"
+        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+        android:textColor="?android:attr/textColorSecondary"/>
+
+    <ImageView
+        android:id="@+id/fingerprint_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_below="@+id/fingerprint_description"
+        android:layout_marginTop="@dimen/fingerprint_margin_horizontal"
+        android:src="@drawable/ic_fp_40px"
+        android:contentDescription="@string/description_fingerprint_icon"/>
+
+    <TextView
+        android:id="@+id/fingerprint_status"
+        style="@android:style/TextAppearance.Material.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBottom="@+id/fingerprint_icon"
+        android:layout_alignTop="@+id/fingerprint_icon"
+        android:layout_marginStart="@dimen/default_margin"
+        android:layout_toEndOf="@+id/fingerprint_icon"
+        android:gravity="center_vertical"
+        android:text="@string/fingerprint_hint"
+        android:textColor="@color/hint_color" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/menu/menu_main.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/menu/menu_main.xml
new file mode 100644
index 0000000..2adf23c
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/menu/menu_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<menu 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"
+    tools:context=".MainActivity">
+    <item
+        android:id="@+id/action_settings"
+        android:orderInCategory="100"
+        android:title="@string/action_settings"
+        app:showAsAction="never" />
+</menu>
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..68c473a
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..fd7e5f6
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..106c0d3
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b319beb
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4dc0ddf
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/values/colors.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..403534e
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/colors.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <color name="warning_color">#f4511e</color>
+    <color name="hint_color">#42000000</color>
+    <color name="success_color">#009688</color>
+    <color name="fingerprint_success">#009688</color>
+    <color name="finerprint_error">#F4511E</color>
+    <color name="fingerprint_fill">#FFFFFF</color>
+    <color name="card_solid">#fefefe</color>
+</resources>
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/values/dimens.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..e2d290b
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/dimens.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <dimen name="fingerprint_square_dimen">40dp</dimen>
+    <dimen name="fingerprint_square_dimen_viewport" type="float">40.0</dimen>
+    <dimen name="card_corner">2dp</dimen>
+    <dimen name="default_elevation">4dp</dimen>
+    <dimen name="logo_square_dimen">150dp</dimen>
+    <dimen name="logo_square_margin">32dp</dimen>
+    <dimen name="default_padding">16dp</dimen>
+    <dimen name="default_margin">16dp</dimen>
+    <dimen name="default_margin_end">4dp</dimen>
+    <dimen name="default_margin_small">8dp</dimen>
+    <dimen name="fingerprint_padding_horizontal">12dp</dimen>
+    <dimen name="fingerprint_padding_vertical">4dp</dimen>
+    <dimen name="fingerprint_margin">24dp</dimen>
+    <dimen name="default_padding_small">8dp</dimen>
+    <dimen name="fingerprint_margin_horizontal">20dp</dimen>
+    <dimen name="fingerprint_margin_vertical">16dp</dimen>
+    <dimen name="default_padding_large">24dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/values/strings.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..09f0376
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/strings.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <!--
+      The similar strings app_name is added in the Application/template directory, but depending
+      on the template directory makes it hard for the sample buildable with Android.mk.
+      Thus defining the application_name with different name from the template.
+    -->
+    <string name="application_name">FingerprintDialog</string>
+    <string name="action_settings">Settings</string>
+    <string name="cancel">Cancel</string>
+    <string name="use_password">Use password</string>
+    <string name="sign_in">Sign in</string>
+    <string name="ok">OK</string>
+    <string name="password">Password</string>
+    <string name="fingerprint_description">Confirm fingerprint to continue</string>
+    <string name="fingerprint_hint">Touch sensor</string>
+    <string name="password_description">Enter your store password to continue</string>
+    <string name="purchase">Purchase</string>
+    <string name="purchase_not_invalidated">Purchase not invalidated</string>
+    <string name="purchase_button_not_invalidated_description">
+        You can proceed to purchase with this button \n even if a new fingerprint is enrolled
+    </string>
+    <string name="fingerprint_not_recognized">Fingerprint not recognized. Try again</string>
+    <string name="fingerprint_success">Fingerprint recognized</string>
+    <string name="item_title">White Mesh Pluto Backpack</string>
+    <string name="item_price">$62.68</string>
+    <string name="item_description">Mesh backpack in white. Black textile trim throughout.</string>
+    <string name="purchase_done">Purchase successful</string>
+    <string name="new_fingerprint_enrolled_description">
+        A new fingerprint was added to this device, so your password is required.
+    </string>
+    <string name="use_fingerprint_in_future">Use fingerprint in the future</string>
+    <string name="use_fingerprint_to_authenticate_title">Use fingerprint to authenticate</string>
+    <string name="use_fingerprint_to_authenticate_key" >use_fingerprint_to_authenticate_key</string>
+    <string name="description_bugdroid_icon">Android bugdroid image</string>
+    <string name="description_fingerprint_icon">Fingerprint icon</string>
+    <string name="register_fingerprint">
+        Go to \'Settings -> Security -> Fingerprint\' and register at least one fingerprint
+    </string>
+    <string name="setup_lock_screen">
+        Secure lock screen hasn\'t set been up.\n
+        Go to \'Settings -> Security -> Fingerprint\' to set up a fingerprint
+    </string>
+</resources>
diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/xml/preferences.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/xml/preferences.xml
new file mode 100644
index 0000000..c9fd74b
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/xml/preferences.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    <CheckBoxPreference
+        android:key="@string/use_fingerprint_to_authenticate_key"
+        android:title="@string/use_fingerprint_to_authenticate_title"
+        android:persistent="true"
+        android:defaultValue="true" />
+</PreferenceScreen>
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/build.gradle b/security/FingerprintDialog/kotlinApp/build.gradle
new file mode 100644
index 0000000..ccd6eb2
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/build.gradle
@@ -0,0 +1,22 @@
+buildscript {
+  ext.kotlin_version = '1.1.60'
+  repositories {
+    google()
+    jcenter()
+  }
+  dependencies {
+    classpath 'com.android.tools.build:gradle:3.0.0'
+    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+  }
+}
+
+allprojects {
+  repositories {
+    google()
+    jcenter()
+  }
+}
+
+task clean(type: Delete) {
+  delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/security/FingerprintDialog/kotlinApp/gradle.properties b/security/FingerprintDialog/kotlinApp/gradle.properties
new file mode 100644
index 0000000..89196d1
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
diff --git a/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..34d5100
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Oct 16 16:01:34 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/security/FingerprintDialog/kotlinApp/gradlew b/security/FingerprintDialog/kotlinApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/security/FingerprintDialog/kotlinApp/gradlew.bat b/security/FingerprintDialog/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/security/FingerprintDialog/kotlinApp/packaging.yaml b/security/FingerprintDialog/kotlinApp/packaging.yaml
new file mode 100644
index 0000000..1846486
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/packaging.yaml
@@ -0,0 +1,23 @@
+
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [security]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-FingerprintDialog
+level:        INTERMEDIATE
+icon:         screenshots/big-icon.png
+apiRefs:
+    - android:android.hardware.fingerprint.FingerprintManager
+    - android:android.hardware.fingerprint.FingerprintManager.AuthenticationCallback
+    - android:android.hardware.fingerprint.FingerprintManager.CryptoObject
+    - android:android.security.KeyGenParameterSpec
+    - android:java.security.KeyStore
+    - android:javax.crypto.Cipher
+    - android:javax.crypto.KeyGenerator
+license: apache2
diff --git a/security/FingerprintDialog/kotlinApp/screenshots/1-purchase-screen.png b/security/FingerprintDialog/kotlinApp/screenshots/1-purchase-screen.png
new file mode 100644
index 0000000..0bf03bd
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/screenshots/1-purchase-screen.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/screenshots/2-fingerprint-dialog.png b/security/FingerprintDialog/kotlinApp/screenshots/2-fingerprint-dialog.png
new file mode 100644
index 0000000..5e681f9
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/screenshots/2-fingerprint-dialog.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/screenshots/3-fingerprint-authenticated.png b/security/FingerprintDialog/kotlinApp/screenshots/3-fingerprint-authenticated.png
new file mode 100644
index 0000000..d485b1d
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/screenshots/3-fingerprint-authenticated.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/screenshots/4-new-fingerprint-enrolled.png b/security/FingerprintDialog/kotlinApp/screenshots/4-new-fingerprint-enrolled.png
new file mode 100644
index 0000000..7dcf080
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/screenshots/4-new-fingerprint-enrolled.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/screenshots/big-icon.png b/security/FingerprintDialog/kotlinApp/screenshots/big-icon.png
new file mode 100644
index 0000000..9e32334
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/screenshots/big-icon.png
Binary files differ
diff --git a/security/FingerprintDialog/kotlinApp/settings.gradle b/security/FingerprintDialog/kotlinApp/settings.gradle
new file mode 100644
index 0000000..4c90568
--- /dev/null
+++ b/security/FingerprintDialog/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'app'
diff --git a/security/keystore/BasicAndroidKeyStore/gradle/wrapper/gradle-wrapper.properties b/security/keystore/BasicAndroidKeyStore/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/security/keystore/BasicAndroidKeyStore/gradle/wrapper/gradle-wrapper.properties
+++ b/security/keystore/BasicAndroidKeyStore/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/sensors/AccelerometerPlay/build.gradle b/sensors/AccelerometerPlay/build.gradle
index 3e47741..2f6b561 100644
--- a/sensors/AccelerometerPlay/build.gradle
+++ b/sensors/AccelerometerPlay/build.gradle
@@ -4,7 +4,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/sensors/AccelerometerPlay/gradle/wrapper/gradle-wrapper.properties b/sensors/AccelerometerPlay/gradle/wrapper/gradle-wrapper.properties
index a209fbe..e3be9a8 100644
--- a/sensors/AccelerometerPlay/gradle/wrapper/gradle-wrapper.properties
+++ b/sensors/AccelerometerPlay/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.properties b/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.properties
+++ b/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/system/AppShortcuts/build.gradle b/system/AppShortcuts/build.gradle
index de4cbd7..ef4eaec 100644
--- a/system/AppShortcuts/build.gradle
+++ b/system/AppShortcuts/build.gradle
@@ -4,7 +4,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/system/AppShortcuts/gradle/wrapper/gradle-wrapper.properties b/system/AppShortcuts/gradle/wrapper/gradle-wrapper.properties
index a3a3b57..ce4e724 100644
--- a/system/AppShortcuts/gradle/wrapper/gradle-wrapper.properties
+++ b/system/AppShortcuts/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.properties b/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.properties
index 4a39e6d..bc82616 100644
--- a/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.properties
+++ b/system/AppUsageStatistics/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/system/RuntimePermissions/build.gradle b/system/RuntimePermissions/build.gradle
index d473b34..f0e71b5 100644
--- a/system/RuntimePermissions/build.gradle
+++ b/system/RuntimePermissions/build.gradle
@@ -4,7 +4,7 @@
     jcenter()
   }
   dependencies {
-    classpath 'com.android.tools.build:gradle:2.3.3'
+    classpath 'com.android.tools.build:gradle:3.0.0'
   }
 }
 
diff --git a/system/RuntimePermissions/gradle/wrapper/gradle-wrapper.properties b/system/RuntimePermissions/gradle/wrapper/gradle-wrapper.properties
index 4a39e6d..bc82616 100644
--- a/system/RuntimePermissions/gradle/wrapper/gradle-wrapper.properties
+++ b/system/RuntimePermissions/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/system/RuntimePermissions/kotlinApp/.google/packaging.yaml b/system/RuntimePermissions/kotlinApp/.google/packaging.yaml
new file mode 100644
index 0000000..50a32ee
--- /dev/null
+++ b/system/RuntimePermissions/kotlinApp/.google/packaging.yaml
@@ -0,0 +1,25 @@
+# Copyright 2018 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [System]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-RuntimePermissions
+level:        BEGINNER
+license:      apache2
diff --git a/system/RuntimePermissions/kotlinApp/README.md b/system/RuntimePermissions/kotlinApp/README.md
new file mode 100644
index 0000000..bbf9188
--- /dev/null
+++ b/system/RuntimePermissions/kotlinApp/README.md
@@ -0,0 +1,84 @@
+
+Android RuntimePermissions Sample (Kotlin)
+==========================================
+
+This sample shows runtime permissions available in Android M and above.
+It shows how to check and request permissions at runtime, handle backwards compatibility using the
+support library and how to declare optional permissions for M-devices only.
+
+Introduction
+------------
+
+Android M introduced runtime permissions. Applications targeting M and above need to request their
+permissions at runtime.
+
+All permissions still need to be declared in the AndroidManifest. However, when accessing APIs that
+require a permission, the Activity or Fragment has to verify that the permission has been granted
+or request the missing permissions using calls through the support library.
+
+Permissions are checked through `ActivityCompat#checkSelfPermission(Context, String)` or
+ContextCompat#checkSelfPermission(Context, String).
+
+Permission are requested through `ActivityCompat#requestPermissions(Activity, String[], int)`, and
+the response received in a callback to
+`ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])`.
+
+Applications can provide an additional rational for the use of permissions after calling
+`ActivityCompat#shouldShowRequestPermissionRationale(Activity,String)`. This call will return true
+if the application should provide the user with more context on why the requested permissions is
+needed, for example if the permission request has been denied before.
+
+If an application targets an SDK below M, all permissions are granted at runtime and are available
+when the application is running. The support library calls handle these checks appropriately.
+However, if permissions have been turned off in the system settings
+for an application targeting an SDK below M, the API will return empty or no data.
+
+Pre-requisites
+--------------
+
+- Android SDK 26
+- Android Support Repository
+
+Screenshots
+-------------
+
+<img src="screenshots/screenshot-1.png" height="400" alt="Screenshot"/>
+<img src="screenshots/screenshot-2.png" height="400" alt="Screenshot"/>
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-RuntimePermissions
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2017 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/system/RuntimePermissions/kotlinApp/build.gradle b/system/RuntimePermissions/kotlinApp/build.gradle
index e1bc7db..9681f78 100644
--- a/system/RuntimePermissions/kotlinApp/build.gradle
+++ b/system/RuntimePermissions/kotlinApp/build.gradle
@@ -6,7 +6,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
diff --git a/system/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/system/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.properties
index c0e49f9..46b169c 100644
--- a/system/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.properties
+++ b/system/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/system/RuntimePermissionsBasic/Application/build.gradle b/system/RuntimePermissionsBasic/Application/build.gradle
new file mode 100644
index 0000000..2a23531
--- /dev/null
+++ b/system/RuntimePermissionsBasic/Application/build.gradle
@@ -0,0 +1,42 @@
+apply plugin: 'com.android.application'
+
+repositories {
+    jcenter()
+    google()
+}
+
+dependencies {
+    compile "com.android.support:support-v4:27.0.2"
+    compile "com.android.support:support-v13:27.0.2"
+    compile "com.android.support:cardview-v7:27.0.2"
+    compile "com.android.support:appcompat-v7:27.0.2"
+    compile 'com.android.support:design:27.0.2'
+}
+
+List<String> dirs = ['main']
+
+android {
+    compileSdkVersion 27
+
+    defaultConfig {
+        minSdkVersion 15
+        targetSdkVersion 27
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_7
+        targetCompatibility JavaVersion.VERSION_1_7
+    }
+
+    sourceSets {
+        main {
+            dirs.each { dir ->
+                java.srcDirs "src/${dir}/java"
+                res.srcDirs "src/${dir}/res"
+            }
+        }
+        androidTest.setRoot('tests')
+        androidTest.java.srcDirs = ['tests/src']
+
+    }
+}
diff --git a/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/MainActivity.java b/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/MainActivity.java
index f534d40..ebc4484 100644
--- a/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/MainActivity.java
+++ b/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/MainActivity.java
@@ -16,20 +16,21 @@
 
 package com.example.android.basicpermissions;
 
-import com.example.android.basicpermissions.camera.CameraPreviewActivity;
-
 import android.Manifest;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 import android.support.design.widget.Snackbar;
 import android.support.v4.app.ActivityCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.view.View;
 import android.widget.Button;
 
+import com.example.android.basicpermissions.camera.CameraPreviewActivity;
+
 /**
  * Launcher Activity that demonstrates the use of runtime permissions for Android M.
  * This Activity requests permissions to access the camera
@@ -66,8 +67,7 @@
         mLayout = findViewById(R.id.main_layout);
 
         // Register a listener for the 'Show Camera Preview' button.
-        Button b = (Button) findViewById(R.id.button_open_camera);
-        b.setOnClickListener(new View.OnClickListener() {
+        findViewById(R.id.button_open_camera).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
                 showCameraPreview();
@@ -76,20 +76,20 @@
     }
 
     @Override
-    public void onRequestPermissionsResult(int requestCode, String[] permissions,
-            int[] grantResults) {
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+            @NonNull int[] grantResults) {
         // BEGIN_INCLUDE(onRequestPermissionsResult)
         if (requestCode == PERMISSION_REQUEST_CAMERA) {
             // Request for camera permission.
             if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                 // Permission has been granted. Start camera preview Activity.
-                Snackbar.make(mLayout, "Camera permission was granted. Starting preview.",
+                Snackbar.make(mLayout, R.string.camera_permission_granted,
                         Snackbar.LENGTH_SHORT)
                         .show();
                 startCamera();
             } else {
                 // Permission request was denied.
-                Snackbar.make(mLayout, "Camera permission request was denied.",
+                Snackbar.make(mLayout, R.string.camera_permission_denied,
                         Snackbar.LENGTH_SHORT)
                         .show();
             }
@@ -104,7 +104,7 @@
                 == PackageManager.PERMISSION_GRANTED) {
             // Permission is already available, start camera preview
             Snackbar.make(mLayout,
-                    "Camera permission is available. Starting preview.",
+                    R.string.camera_permission_available,
                     Snackbar.LENGTH_SHORT).show();
             startCamera();
         } else {
@@ -125,9 +125,9 @@
                 Manifest.permission.CAMERA)) {
             // Provide an additional rationale to the user if the permission was not granted
             // and the user would benefit from additional context for the use of the permission.
-            // Display a SnackBar with a button to request the missing permission.
-            Snackbar.make(mLayout, "Camera access is required to display the camera preview.",
-                    Snackbar.LENGTH_INDEFINITE).setAction("OK", new View.OnClickListener() {
+            // Display a SnackBar with cda button to request the missing permission.
+            Snackbar.make(mLayout, R.string.camera_access_required,
+                    Snackbar.LENGTH_INDEFINITE).setAction(R.string.ok, new View.OnClickListener() {
                 @Override
                 public void onClick(View view) {
                     // Request the permission
@@ -138,12 +138,10 @@
             }).show();
 
         } else {
-            Snackbar.make(mLayout,
-                    "Permission is not available. Requesting camera permission.",
-                    Snackbar.LENGTH_SHORT).show();
+            Snackbar.make(mLayout, R.string.camera_unavailable, Snackbar.LENGTH_SHORT).show();
             // Request the permission. The result will be received in onRequestPermissionResult().
-            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
-                    PERMISSION_REQUEST_CAMERA);
+            ActivityCompat.requestPermissions(this,
+                    new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
         }
     }
 
diff --git a/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreview.java b/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreview.java
index 7abf2d8..db8eacf 100644
--- a/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreview.java
+++ b/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreview.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.hardware.Camera;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Surface;
 import android.view.SurfaceHolder;
@@ -27,7 +28,7 @@
 
 /**
  * Camera preview that displays a {@link Camera}.
- *
+ * <p>
  * Handles basic lifecycle methods to display and stop the preview.
  * <p>
  * Implementation is based directly on the documentation at
@@ -36,14 +37,19 @@
 public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
 
     private static final String TAG = "CameraPreview";
+
     private SurfaceHolder mHolder;
     private Camera mCamera;
     private Camera.CameraInfo mCameraInfo;
     private int mDisplayOrientation;
 
-    public CameraPreview(Context context, Camera camera, Camera.CameraInfo cameraInfo,
-            int displayOrientation) {
-        super(context);
+    public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, null, null, 0);
+    }
+
+    public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr,
+            Camera camera, Camera.CameraInfo cameraInfo, int displayOrientation) {
+        super(context, attrs, defStyleAttr);
 
         // Do not initialise if no camera has been set
         if (camera == null || cameraInfo == null) {
@@ -59,6 +65,41 @@
         mHolder.addCallback(this);
     }
 
+    /**
+     * Calculate the correct orientation for a {@link Camera} preview that is displayed on screen.
+     * <p>
+     * Implementation is based on the sample code provided in
+     * {@link Camera#setDisplayOrientation(int)}.
+     */
+    public static int calculatePreviewOrientation(Camera.CameraInfo info, int rotation) {
+        int degrees = 0;
+
+        switch (rotation) {
+            case Surface.ROTATION_0:
+                degrees = 0;
+                break;
+            case Surface.ROTATION_90:
+                degrees = 90;
+                break;
+            case Surface.ROTATION_180:
+                degrees = 180;
+                break;
+            case Surface.ROTATION_270:
+                degrees = 270;
+                break;
+        }
+
+        int result;
+        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+            result = (info.orientation + degrees) % 360;
+            result = (360 - result) % 360;  // compensate the mirror
+        } else {  // back-facing
+            result = (info.orientation - degrees + 360) % 360;
+        }
+
+        return result;
+    }
+
     public void surfaceCreated(SurfaceHolder holder) {
         // The Surface has been created, now tell the camera where to draw the preview.
         try {
@@ -104,39 +145,4 @@
             Log.d(TAG, "Error starting camera preview: " + e.getMessage());
         }
     }
-
-    /**
-     * Calculate the correct orientation for a {@link Camera} preview that is displayed on screen.
-     *
-     * Implementation is based on the sample code provided in
-     * {@link Camera#setDisplayOrientation(int)}.
-     */
-    public static int calculatePreviewOrientation(Camera.CameraInfo info, int rotation) {
-        int degrees = 0;
-
-        switch (rotation) {
-            case Surface.ROTATION_0:
-                degrees = 0;
-                break;
-            case Surface.ROTATION_90:
-                degrees = 90;
-                break;
-            case Surface.ROTATION_180:
-                degrees = 180;
-                break;
-            case Surface.ROTATION_270:
-                degrees = 270;
-                break;
-        }
-
-        int result;
-        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
-            result = (info.orientation + degrees) % 360;
-            result = (360 - result) % 360;  // compensate the mirror
-        } else {  // back-facing
-            result = (info.orientation - degrees + 360) % 360;
-        }
-
-        return result;
-    }
 }
diff --git a/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreviewActivity.java b/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreviewActivity.java
index ee589d9..d7981d8 100644
--- a/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreviewActivity.java
+++ b/system/RuntimePermissionsBasic/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreviewActivity.java
@@ -16,14 +16,15 @@
 
 package com.example.android.basicpermissions.camera;
 
-import com.example.android.basicpermissions.R;
-
 import android.app.Activity;
 import android.hardware.Camera;
 import android.os.Bundle;
+import android.util.Log;
 import android.widget.FrameLayout;
 import android.widget.Toast;
 
+import com.example.android.basicpermissions.R;
+
 /**
  * Displays a {@link CameraPreview} of the first {@link Camera}.
  * An error message is displayed if the Camera is not available.
@@ -36,15 +37,12 @@
  * http://developer.android.com/guide/topics/media/camera.html
  */
 public class CameraPreviewActivity extends Activity {
-
-    private static final String TAG = "CameraPreview";
-
+    private static final String TAG = "CameraPreviewActivity";
     /**
      * Id of the camera to access. 0 is the first camera.
      */
     private static final int CAMERA_ID = 0;
 
-    private CameraPreview mPreview;
     private Camera mCamera;
 
     @Override
@@ -56,22 +54,21 @@
         Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
         Camera.getCameraInfo(CAMERA_ID, cameraInfo);
 
-        if (mCamera == null || cameraInfo == null) {
+        if (mCamera == null) {
             // Camera is not available, display error message
-            Toast.makeText(this, "Camera is not available.", Toast.LENGTH_SHORT).show();
             setContentView(R.layout.activity_camera_unavailable);
         } else {
 
             setContentView(R.layout.activity_camera);
 
             // Get the rotation of the screen to adjust the preview image accordingly.
-            final int displayRotation = getWindowManager().getDefaultDisplay()
-                    .getRotation();
+            int displayRotation = getWindowManager().getDefaultDisplay().getRotation();
 
             // Create the Preview view and set it as the content of this Activity.
-            mPreview = new CameraPreview(this, mCamera, cameraInfo, displayRotation);
-            FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
-            preview.addView(mPreview);
+            CameraPreview cameraPreview = new CameraPreview(this, null,
+                    0, mCamera, cameraInfo, displayRotation);
+            FrameLayout preview = findViewById(R.id.camera_preview);
+            preview.addView(cameraPreview);
         }
     }
 
@@ -82,22 +79,26 @@
         releaseCamera();
     }
 
-    /** A safe way to get an instance of the Camera object. */
+    /**
+     * A safe way to get an instance of the Camera object.
+     */
     private Camera getCameraInstance(int cameraId) {
         Camera c = null;
         try {
             c = Camera.open(cameraId); // attempt to get a Camera instance
         } catch (Exception e) {
             // Camera is not available (in use or does not exist)
-            Toast.makeText(this, "Camera " + cameraId + " is not available: " + e.getMessage(),
-                    Toast.LENGTH_SHORT).show();
+            Log.e(TAG, "Camera " + cameraId + " is not available: " + e.getMessage());
         }
         return c; // returns null if camera is unavailable
     }
 
+    /**
+     * Release the camera for other applications.
+     */
     private void releaseCamera() {
         if (mCamera != null) {
-            mCamera.release();        // release the camera for other applications
+            mCamera.release();
             mCamera = null;
         }
     }
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/drawable-hdpi/tile.9.png b/system/RuntimePermissionsBasic/Application/src/main/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_camera.xml b/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_camera.xml
index b12eee1..1329717 100644
--- a/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_camera.xml
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_camera.xml
@@ -1,5 +1,5 @@
 <!--
- Copyright 2015 The Android Open Source Project
+ Copyright 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.
@@ -15,8 +15,7 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/camera_preview"
-             android:layout_width="fill_parent"
-             android:layout_height="fill_parent"
-             android:layout_weight="1"
-        />
+    android:id="@+id/camera_preview"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:layout_weight="1" />
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_camera_unavailable.xml b/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_camera_unavailable.xml
index af0efe5..0f9ecb9 100644
--- a/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_camera_unavailable.xml
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_camera_unavailable.xml
@@ -1,5 +1,5 @@
 <!--
- Copyright 2015 The Android Open Source Project
+ Copyright 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.
@@ -15,23 +15,16 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:paddingLeft="@dimen/horizontal_page_margin"
-              android:paddingRight="@dimen/horizontal_page_margin"
-              android:paddingTop="@dimen/vertical_page_margin"
-              android:paddingBottom="@dimen/vertical_page_margin">
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/vertical_page_margin"
+    android:paddingLeft="@dimen/horizontal_page_margin"
+    android:paddingRight="@dimen/horizontal_page_margin"
+    android:paddingTop="@dimen/vertical_page_margin">
 
-    <ScrollView
-            android:layout_width="match_parent"
-            android:layout_height="fill_parent">
-
-        <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/camera_unavailable"/>
-
-    </ScrollView>
-
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/camera_unavailable" />
 </LinearLayout>
\ No newline at end of file
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_main.xml b/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_main.xml
index 146b8b1..838bbea 100644
--- a/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_main.xml
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/layout/activity_main.xml
@@ -14,9 +14,9 @@
  limitations under the License.
 -->
 
-<LinearLayout android:id="@+id/main_layout"
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/main_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
@@ -32,10 +32,9 @@
         android:layout_marginBottom="@dimen/horizontal_page_margin"
         android:text="@string/intro" />
 
-
     <Button
         android:id="@+id/button_open_camera"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:text="Open Camera Preview" />
+        android:text="@string/open_camera_preview" />
 </LinearLayout>
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/values-sw600dp/dimens.xml b/system/RuntimePermissionsBasic/Application/src/main/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..9a0875e
--- /dev/null
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/values-sw600dp/styles.xml b/system/RuntimePermissionsBasic/Application/src/main/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..04fbedf
--- /dev/null
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/values-sw600dp/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/values-v11/styles.xml b/system/RuntimePermissionsBasic/Application/src/main/res/values-v11/styles.xml
new file mode 100644
index 0000000..447ef8b
--- /dev/null
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/values-v11/styles.xml
@@ -0,0 +1,22 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/values-v21/styles.xml b/system/RuntimePermissionsBasic/Application/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..f9074f7
--- /dev/null
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/values-v21/styles.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <style name="Theme.Base" parent="android:Theme.Material.Light" />
+</resources>
\ No newline at end of file
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/values/dimens.xml b/system/RuntimePermissionsBasic/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..ffa67a6
--- /dev/null
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/values/strings.xml b/system/RuntimePermissionsBasic/Application/src/main/res/values/strings.xml
index eb0b7c4..bc6b386 100644
--- a/system/RuntimePermissionsBasic/Application/src/main/res/values/strings.xml
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/values/strings.xml
@@ -1,6 +1,36 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
 <resources>
     <string name="show_camera">Show camera preview</string>
     <string name="camera_unavailable"><b>Camera could not be opened.</b>\nThis occurs when the camera is not available (for example it is already in use) or if the system has denied access (for example when camera access has been disabled).</string>
     <string name="intro">This sample shows a basic implementation for requesting permissions at runtime.\nClick the button below to request the Camera permission and open a full-screen camera preview.</string>
+    <string name="open_camera_preview">Open Camera Preview</string>
+    <string name="app_name">RuntimePermissionsBasic</string>
+    <string name="intro_message"><![CDATA[
+This sample shows a basic implementation for requesting permissions at runtime. Click the button to
+request the Camera permission and open a full-screen camera preview.
 
+Note: The "RuntimePermissions" sample provides a more complete overview over the runtime permission
+features available.]]>
+    </string>
+    <string name="camera_access_required">Camera access is required to display the camera preview.</string>
+    <string name="ok">OK</string>
+    <string name="camera_permission_not_available">Permission is not available. Requesting camera permission.</string>
+    <string name="camera_permission_available">Camera permission is available. Starting preview.</string>
+    <string name="camera_permission_granted">Camera permission was granted. Starting preview.</string>
+    <string name="camera_permission_denied">Camera permission request was denied.</string>
 </resources>
diff --git a/system/RuntimePermissionsBasic/Application/src/main/res/values/styles.xml b/system/RuntimePermissionsBasic/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..d88caa5
--- /dev/null
+++ b/system/RuntimePermissionsBasic/Application/src/main/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/system/RuntimePermissionsBasic/build.gradle b/system/RuntimePermissionsBasic/build.gradle
index 2b8d1ef..b063483 100644
--- a/system/RuntimePermissionsBasic/build.gradle
+++ b/system/RuntimePermissionsBasic/build.gradle
@@ -1,3 +1,13 @@
+buildscript {
+    repositories {
+        jcenter()
+        google()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+    }
+}
 
 // BEGIN_EXCLUDE
 import com.example.android.samples.build.SampleGenPlugin
diff --git a/system/RuntimePermissionsBasic/gradle/wrapper/gradle-wrapper.properties b/system/RuntimePermissionsBasic/gradle/wrapper/gradle-wrapper.properties
index 4a39e6d..1213f38 100644
--- a/system/RuntimePermissionsBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/system/RuntimePermissionsBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/build.gradle b/system/RuntimePermissionsBasic/kotlinApp/Application/build.gradle
new file mode 100644
index 0000000..fb02cef
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/build.gradle
@@ -0,0 +1,44 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+repositories {
+    jcenter()
+    google()
+}
+
+dependencies {
+    compile "com.android.support:support-v4:27.0.2"
+    compile "com.android.support:support-v13:27.0.2"
+    compile "com.android.support:cardview-v7:27.0.2"
+    compile "com.android.support:appcompat-v7:27.0.2"
+    compile 'com.android.support:design:27.0.2'
+    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
+
+List<String> dirs = ['main']
+
+android {
+
+    compileSdkVersion 27
+
+    defaultConfig {
+        minSdkVersion 15
+        targetSdkVersion 27
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_7
+        targetCompatibility JavaVersion.VERSION_1_7
+    }
+
+    sourceSets {
+        main {
+            dirs.each { dir ->
+                java.srcDirs "src/${dir}/java"
+                res.srcDirs "src/${dir}/res"
+            }
+        }
+        androidTest.setRoot('tests')
+        androidTest.java.srcDirs = ['tests/src']
+    }
+}
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/AndroidManifest.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..bfae9b9
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.example.android.basicpermissions">
+
+    <!-- BEGIN_INCLUDE(manifest) -->
+
+    <!-- Note that all required permissions are declared here in the Android manifest.
+     On Android M and above, use of these permissions is only requested at run time. -->
+    <uses-permission android:name="android.permission.CAMERA"/>
+    <!-- END_INCLUDE(manifest) -->
+
+    <application
+            android:allowBackup="true"
+            android:icon="@mipmap/ic_launcher"
+            android:label="@string/app_name"
+            android:theme="@style/Theme.AppCompat.Light">
+        <activity
+                android:name=".MainActivity"
+                android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
+        <!-- Activity that only displays the camera preview. -->
+        <activity
+                android:name=".camera.CameraPreviewActivity"
+                android:exported="false"/>
+
+    </application>
+
+</manifest>
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/MainActivity.kt b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/MainActivity.kt
new file mode 100644
index 0000000..d20e0bc
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/MainActivity.kt
@@ -0,0 +1,128 @@
+/*
+* Copyright 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 com.example.android.basicpermissions
+
+import android.Manifest
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.support.design.widget.Snackbar
+import android.support.v4.app.ActivityCompat
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import android.widget.Button
+import com.example.android.basicpermissions.camera.CameraPreviewActivity
+import com.example.android.basicpermissions.util.checkSelfPermissionCompat
+import com.example.android.basicpermissions.util.requestPermissionsCompat
+import com.example.android.basicpermissions.util.shouldShowRequestPermissionRationaleCompat
+import com.example.android.basicpermissions.util.showSnackbar
+
+const val PERMISSION_REQUEST_CAMERA = 0
+
+/**
+ * Launcher Activity that demonstrates the use of runtime permissions for Android M.
+ * This Activity requests permissions to access the camera
+ * ([android.Manifest.permission.CAMERA])
+ * when the 'Show Camera Preview' button is clicked to start  [CameraPreviewActivity] once
+ * the permission has been granted.
+ *
+ * <p>First, the status of the Camera permission is checked using [ActivityCompat.checkSelfPermission]
+ * If it has not been granted ([PackageManager.PERMISSION_GRANTED]), it is requested by
+ * calling [ActivityCompat.requestPermissions]. The result of the request is
+ * returned to the
+ * [android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback], which starts
+ * if the permission has been granted.
+ *
+ * <p>Note that there is no need to check the API level, the support library
+ * already takes care of this. Similar helper methods for permissions are also available in
+ * ([ActivityCompat],
+ * [android.support.v4.content.ContextCompat] and [android.support.v4.app.Fragment]).
+ */
+class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback {
+
+    private lateinit var layout: View
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+        layout = findViewById(R.id.main_layout)
+
+        // Register a listener for the 'Show Camera Preview' button.
+        findViewById<Button>(R.id.button_open_camera).setOnClickListener { showCameraPreview() }
+    }
+
+    override fun onRequestPermissionsResult(
+            requestCode: Int,
+            permissions: Array<String>,
+            grantResults: IntArray
+    ) {
+        if (requestCode == PERMISSION_REQUEST_CAMERA) {
+            // Request for camera permission.
+            if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+                // Permission has been granted. Start camera preview Activity.
+                layout.showSnackbar(R.string.camera_permission_granted, Snackbar.LENGTH_SHORT)
+                startCamera()
+            } else {
+                // Permission request was denied.
+                layout.showSnackbar(R.string.camera_permission_denied, Snackbar.LENGTH_SHORT)
+            }
+        }
+    }
+
+    private fun showCameraPreview() {
+        // Check if the Camera permission has been granted
+        if (checkSelfPermissionCompat(Manifest.permission.CAMERA) ==
+                PackageManager.PERMISSION_GRANTED) {
+            // Permission is already available, start camera preview
+            layout.showSnackbar(R.string.camera_permission_available, Snackbar.LENGTH_SHORT)
+            startCamera()
+        } else {
+            // Permission is missing and must be requested.
+            requestCameraPermission()
+        }
+    }
+
+    /**
+     * Requests the [android.Manifest.permission.CAMERA] permission.
+     * If an additional rationale should be displayed, the user has to launch the request from
+     * a SnackBar that includes additional information.
+     */
+    private fun requestCameraPermission() {
+        // Permission has not been granted and must be requested.
+        if (shouldShowRequestPermissionRationaleCompat(Manifest.permission.CAMERA)) {
+            // Provide an additional rationale to the user if the permission was not granted
+            // and the user would benefit from additional context for the use of the permission.
+            // Display a SnackBar with a button to request the missing permission.
+            layout.showSnackbar(R.string.camera_access_required,
+                    Snackbar.LENGTH_INDEFINITE, R.string.ok) {
+                requestPermissionsCompat(arrayOf(Manifest.permission.CAMERA),
+                        PERMISSION_REQUEST_CAMERA)
+            }
+
+        } else {
+            layout.showSnackbar(R.string.camera_permission_not_available, Snackbar.LENGTH_SHORT)
+
+            // Request the permission. The result will be received in onRequestPermissionResult().
+            requestPermissionsCompat(arrayOf(Manifest.permission.CAMERA), PERMISSION_REQUEST_CAMERA)
+        }
+    }
+
+    private fun startCamera() {
+        val intent = Intent(this, CameraPreviewActivity::class.java)
+        startActivity(intent)
+    }
+}
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreview.kt b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreview.kt
new file mode 100644
index 0000000..25b8288
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreview.kt
@@ -0,0 +1,101 @@
+/*
+* Copyright 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 com.example.android.basicpermissions.camera
+
+import android.content.Context
+import android.hardware.Camera
+import android.util.AttributeSet
+import android.util.Log
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import com.example.android.basicpermissions.util.calculatePreviewOrientation
+
+import java.io.IOException
+
+/**
+ * Camera preview that displays a [Camera].
+ *
+ *
+ * Handles basic lifecycle methods to display and stop the preview.
+ *
+ *
+ * Implementation is based directly on the documentation at
+ * http://developer.android.com/guide/topics/media/camera.html
+ */
+class CameraPreview @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyleAttr: Int = 0,
+        private val camera: Camera? = null,
+        private val cameraInfo: Camera.CameraInfo? = null,
+        private val displayOrientation: Int = 0
+) : SurfaceView(context, attrs, defStyleAttr), SurfaceHolder.Callback {
+
+    init {
+
+        // Do not initialise if no camera has been set
+        if (camera != null && cameraInfo != null) {
+            // Install a SurfaceHolder.Callback so we get notified when the
+            // underlying surface is created and destroyed.
+            holder.addCallback(this@CameraPreview)
+        }
+    }
+
+    override fun surfaceCreated(holder: SurfaceHolder) {
+        // The Surface has been created, now tell the camera where to draw the preview.
+        try {
+            camera?.run {
+                setPreviewDisplay(holder)
+                startPreview()
+            }
+            Log.d(TAG, "Camera preview started.")
+        } catch (e: IOException) {
+            Log.d(TAG, "Error setting camera preview: ${e.message}")
+        }
+
+    }
+
+    override fun surfaceDestroyed(holder: SurfaceHolder) {
+        // empty. Take care of releasing the Camera preview in your activity.
+    }
+
+    override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
+        // If your preview can change or rotate, take care of those events here.
+        // Make sure to stop the preview before resizing or reformatting it.
+
+        if (holder.surface == null) {
+            // preview surface does not exist
+            Log.d(TAG, "Preview surface does not exist")
+            return
+        }
+        Log.d(TAG, "Preview stopped.")
+        camera?.run {
+            // stop preview before making changes
+            stopPreview()
+            cameraInfo?.let {
+                setDisplayOrientation(it.calculatePreviewOrientation(displayOrientation))
+            }
+            setPreviewDisplay(holder)
+            startPreview()
+            Log.d(TAG, "Camera preview started.")
+        }
+    }
+
+    companion object {
+        private val TAG = "CameraPreview"
+    }
+}
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreviewActivity.kt b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreviewActivity.kt
new file mode 100644
index 0000000..3d5c1a2
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreviewActivity.kt
@@ -0,0 +1,95 @@
+/*
+* Copyright 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 com.example.android.basicpermissions.camera
+
+import android.hardware.Camera
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.util.Log
+import android.widget.FrameLayout
+import com.example.android.basicpermissions.R
+
+private const val TAG = "CameraPreviewActivity"
+private const val CAMERA_ID = 0
+
+/**
+ * Displays a [CameraPreview] of the first [Camera].
+ * An error message is displayed if the Camera is not available.
+ *
+ *
+ * This Activity is only used to illustrate that access to the Camera API has been granted (or
+ * denied) as part of the runtime permissions model. It is not relevant for the use of the
+ * permissions API.
+ *
+ *
+ * Implementation is based directly on the documentation at
+ * http://developer.android.com/guide/topics/media/camera.html
+ */
+class CameraPreviewActivity : AppCompatActivity() {
+
+    private var camera: Camera? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        // Open an instance of the first camera and retrieve its info.
+        camera = getCameraInstance(CAMERA_ID)
+        val cameraInfo = Camera.CameraInfo()
+        Camera.getCameraInfo(CAMERA_ID, cameraInfo)
+
+        if (camera == null) {
+            // Camera is not available, display error message.
+            setContentView(R.layout.activity_camera_unavailable)
+        } else {
+            setContentView(R.layout.activity_camera)
+
+            // Get the rotation of the screen to adjust the preview image accordingly.
+            val displayRotation = windowManager.defaultDisplay.rotation
+
+            // Create the Preview view and set it as the content of this Activity.
+            val cameraPreview = CameraPreview(this, null,
+                    0, camera, cameraInfo, displayRotation)
+            findViewById<FrameLayout>(R.id.camera_preview).addView(cameraPreview)
+        }
+    }
+
+    public override fun onPause() {
+        super.onPause()
+        // Stop camera access
+        releaseCamera()
+    }
+
+    /**
+     * A safe way to get an instance of the Camera object.
+     */
+    private fun getCameraInstance(cameraId: Int): Camera? {
+        var c: Camera? = null
+        try {
+            c = Camera.open(cameraId) // attempt to get a Camera instance
+        } catch (e: Exception) {
+            // Camera is not available (in use or does not exist)
+            Log.e(TAG, "Camera $cameraId is not available: ${e.message}")
+        }
+
+        return c // returns null if camera is unavailable
+    }
+
+    private fun releaseCamera() {
+        camera?.release()
+        camera = null
+    }
+}
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/util/AppCompatActivityExt.kt b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/util/AppCompatActivityExt.kt
new file mode 100644
index 0000000..d5c2a41
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/util/AppCompatActivityExt.kt
@@ -0,0 +1,31 @@
+/*
+* Copyright 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 com.example.android.basicpermissions.util
+
+import android.support.v4.app.ActivityCompat
+import android.support.v7.app.AppCompatActivity
+
+fun AppCompatActivity.checkSelfPermissionCompat(permission: String) =
+        ActivityCompat.checkSelfPermission(this, permission)
+
+fun AppCompatActivity.shouldShowRequestPermissionRationaleCompat(permission: String) =
+        ActivityCompat.shouldShowRequestPermissionRationale(this, permission)
+
+fun AppCompatActivity.requestPermissionsCompat(permissionsArray: Array<String>,
+        requestCode: Int) {
+    ActivityCompat.requestPermissions(this, permissionsArray, requestCode)
+}
\ No newline at end of file
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/util/CameraExt.kt b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/util/CameraExt.kt
new file mode 100644
index 0000000..478f1d8
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/util/CameraExt.kt
@@ -0,0 +1,38 @@
+/*
+* Copyright 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 com.example.android.basicpermissions.util
+
+import android.hardware.Camera
+import android.view.Surface
+
+fun Camera.CameraInfo.calculatePreviewOrientation(rotation: Int): Int {
+    val degrees = when (rotation) {
+        Surface.ROTATION_0 -> 0
+        Surface.ROTATION_90 -> 90
+        Surface.ROTATION_180 -> 180
+        Surface.ROTATION_270 -> 270
+        else -> 0
+    }
+
+    return if (facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+        // compensate the mirror
+        360 - ((orientation + degrees) % 360) % 360
+    } else {
+        // back-facing
+        (orientation - degrees + 360) % 360
+    }
+}
\ No newline at end of file
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/util/ViewExt.kt b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/util/ViewExt.kt
new file mode 100644
index 0000000..0da548f
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/java/com/example/android/basicpermissions/util/ViewExt.kt
@@ -0,0 +1,51 @@
+/*
+* Copyright 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 com.example.android.basicpermissions.util
+
+import android.support.design.widget.Snackbar
+import android.view.View
+
+fun View.showSnackbar(msgId: Int, length: Int) {
+    showSnackbar(context.getString(msgId), length)
+}
+
+fun View.showSnackbar(msg: String, length: Int) {
+    showSnackbar(msg, length, null, {})
+}
+
+fun View.showSnackbar(
+        msgId: Int,
+        length: Int,
+        actionMessageId: Int,
+        action: (View) -> Unit
+) {
+    showSnackbar(context.getString(msgId), length, context.getString(actionMessageId), action)
+}
+
+fun View.showSnackbar(
+        msg: String,
+        length: Int,
+        actionMessage: CharSequence?,
+        action: (View) -> Unit
+) {
+    val snackbar = Snackbar.make(this, msg, length)
+    if (actionMessage != null) {
+        snackbar.setAction(actionMessage) {
+            action(this)
+        }.show()
+    }
+}
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/layout/activity_camera.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/layout/activity_camera.xml
new file mode 100644
index 0000000..1329717
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/layout/activity_camera.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/camera_preview"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:layout_weight="1" />
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/layout/activity_camera_unavailable.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/layout/activity_camera_unavailable.xml
new file mode 100644
index 0000000..0f9ecb9
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/layout/activity_camera_unavailable.xml
@@ -0,0 +1,30 @@
+<!--
+ Copyright 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/vertical_page_margin"
+    android:paddingLeft="@dimen/horizontal_page_margin"
+    android:paddingRight="@dimen/horizontal_page_margin"
+    android:paddingTop="@dimen/vertical_page_margin">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/camera_unavailable" />
+</LinearLayout>
\ No newline at end of file
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/layout/activity_main.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..838bbea
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/layout/activity_main.xml
@@ -0,0 +1,40 @@
+<!--
+ 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/main_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/vertical_page_margin"
+    android:paddingLeft="@dimen/horizontal_page_margin"
+    android:paddingRight="@dimen/horizontal_page_margin"
+    android:paddingTop="@dimen/vertical_page_margin"
+    tools:context=".MainActivity">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/horizontal_page_margin"
+        android:text="@string/intro" />
+
+    <Button
+        android:id="@+id/button_open_camera"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/open_camera_preview" />
+</LinearLayout>
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-hdpi/ic_launcher.png b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a7cee76
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-mdpi/ic_launcher.png b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..378d029
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-xhdpi/ic_launcher.png b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..c898742
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..ad4f1df
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..484f298
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-sw600dp/dimens.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..9a0875e
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-sw600dp/styles.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..04fbedf
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-sw600dp/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-v11/styles.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-v11/styles.xml
new file mode 100644
index 0000000..447ef8b
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-v11/styles.xml
@@ -0,0 +1,22 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-v21/styles.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..f9074f7
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values-v21/styles.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <style name="Theme.Base" parent="android:Theme.Material.Light" />
+</resources>
\ No newline at end of file
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values/dimens.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..ffa67a6
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values/strings.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..bc6b386
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values/strings.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="show_camera">Show camera preview</string>
+    <string name="camera_unavailable"><b>Camera could not be opened.</b>\nThis occurs when the camera is not available (for example it is already in use) or if the system has denied access (for example when camera access has been disabled).</string>
+    <string name="intro">This sample shows a basic implementation for requesting permissions at runtime.\nClick the button below to request the Camera permission and open a full-screen camera preview.</string>
+    <string name="open_camera_preview">Open Camera Preview</string>
+    <string name="app_name">RuntimePermissionsBasic</string>
+    <string name="intro_message"><![CDATA[
+This sample shows a basic implementation for requesting permissions at runtime. Click the button to
+request the Camera permission and open a full-screen camera preview.
+
+Note: The "RuntimePermissions" sample provides a more complete overview over the runtime permission
+features available.]]>
+    </string>
+    <string name="camera_access_required">Camera access is required to display the camera preview.</string>
+    <string name="ok">OK</string>
+    <string name="camera_permission_not_available">Permission is not available. Requesting camera permission.</string>
+    <string name="camera_permission_available">Camera permission is available. Starting preview.</string>
+    <string name="camera_permission_granted">Camera permission was granted. Starting preview.</string>
+    <string name="camera_permission_denied">Camera permission request was denied.</string>
+</resources>
diff --git a/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values/styles.xml b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..d88caa5
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/Application/src/main/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/system/RuntimePermissionsBasic/kotlinApp/build.gradle b/system/RuntimePermissionsBasic/kotlinApp/build.gradle
new file mode 100644
index 0000000..2062e14
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/build.gradle
@@ -0,0 +1,13 @@
+buildscript {
+    ext.kotlin_version = '1.2.0'
+    repositories {
+        jcenter()
+        mavenCentral()
+        google()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
diff --git a/system/RuntimePermissionsBasic/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/system/RuntimePermissionsBasic/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/system/RuntimePermissionsBasic/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/system/RuntimePermissionsBasic/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..fcae5ca
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sun Dec 07 22:52:45 JST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
\ No newline at end of file
diff --git a/system/RuntimePermissionsBasic/kotlinApp/gradlew b/system/RuntimePermissionsBasic/kotlinApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/system/RuntimePermissionsBasic/kotlinApp/gradlew.bat b/system/RuntimePermissionsBasic/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windowz variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+if "%@eval[2+2]" == "4" goto 4NT_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+goto execute

+

+:4NT_args

+@rem Get arguments from the 4NT Shell from JP Software

+set CMD_LINE_ARGS=%$

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/system/RuntimePermissionsBasic/kotlinApp/screenshots/big_icon.png b/system/RuntimePermissionsBasic/kotlinApp/screenshots/big_icon.png
new file mode 100644
index 0000000..14c53b6
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/screenshots/big_icon.png
Binary files differ
diff --git a/system/RuntimePermissionsBasic/kotlinApp/screenshots/screenshot-1.png b/system/RuntimePermissionsBasic/kotlinApp/screenshots/screenshot-1.png
new file mode 100644
index 0000000..6c31c38
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/screenshots/screenshot-1.png
Binary files differ
diff --git a/system/RuntimePermissionsBasic/kotlinApp/settings.gradle b/system/RuntimePermissionsBasic/kotlinApp/settings.gradle
new file mode 100644
index 0000000..9464a35
--- /dev/null
+++ b/system/RuntimePermissionsBasic/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'Application'
diff --git a/system/RuntimePermissionsBasic/template-params.xml b/system/RuntimePermissionsBasic/template-params.xml
index aba6ac8..0dae4df 100644
--- a/system/RuntimePermissionsBasic/template-params.xml
+++ b/system/RuntimePermissionsBasic/template-params.xml
@@ -21,9 +21,6 @@
 
     <minSdk>15</minSdk>
 
-    <dependency>com.android.support:support-v4:24.0.0</dependency>
-    <dependency>com.android.support:design:24.0.0</dependency>
-
     <strings>
         <intro>
             <![CDATA[
@@ -33,7 +30,7 @@
         </intro>
     </strings>
 
-    <template src="base"/>
+    <template src="base-build"/>
 
     <metadata>
         <status>PUBLISHED</status>
diff --git a/testing/ActivityInstrumentation/gradle/wrapper/gradle-wrapper.properties b/testing/ActivityInstrumentation/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/testing/ActivityInstrumentation/gradle/wrapper/gradle-wrapper.properties
+++ b/testing/ActivityInstrumentation/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/tv/ChannelsPrograms/gradle/wrapper/gradle-wrapper.properties b/tv/ChannelsPrograms/gradle/wrapper/gradle-wrapper.properties
index fcc67a3..3cbfa20 100644
--- a/tv/ChannelsPrograms/gradle/wrapper/gradle-wrapper.properties
+++ b/tv/ChannelsPrograms/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-rc-1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/ui/DrawableTinting/gradle/wrapper/gradle-wrapper.properties b/ui/DrawableTinting/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/DrawableTinting/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/DrawableTinting/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/Interpolator/gradle/wrapper/gradle-wrapper.properties b/ui/Interpolator/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/Interpolator/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/Interpolator/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/accessibility/BasicAccessibility/gradle/wrapper/gradle-wrapper.properties b/ui/accessibility/BasicAccessibility/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/accessibility/BasicAccessibility/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/accessibility/BasicAccessibility/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/actionbar/DoneBar/gradle/wrapper/gradle-wrapper.properties b/ui/actionbar/DoneBar/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/actionbar/DoneBar/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/actionbar/DoneBar/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/actionbarcompat/ActionBarCompat-Basic/gradle/wrapper/gradle-wrapper.properties b/ui/actionbarcompat/ActionBarCompat-Basic/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/actionbarcompat/ActionBarCompat-Basic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/actionbarcompat/ActionBarCompat-Basic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/gradle/wrapper/gradle-wrapper.properties b/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/gradle/wrapper/gradle-wrapper.properties b/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/actionbarcompat/ActionBarCompat-SearchView/build.gradle b/ui/actionbarcompat/ActionBarCompat-SearchView/build.gradle
index 68f2314..ec71e58 100644
--- a/ui/actionbarcompat/ActionBarCompat-SearchView/build.gradle
+++ b/ui/actionbarcompat/ActionBarCompat-SearchView/build.gradle
@@ -4,7 +4,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/ui/actionbarcompat/ActionBarCompat-Styled/gradle/wrapper/gradle-wrapper.properties b/ui/actionbarcompat/ActionBarCompat-Styled/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/actionbarcompat/ActionBarCompat-Styled/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/actionbarcompat/ActionBarCompat-Styled/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/gradle/wrapper/gradle-wrapper.properties b/ui/activityscenetransition/ActivitySceneTransitionBasic/gradle/wrapper/gradle-wrapper.properties
index aa3b089..cf959fc 100644
--- a/ui/activityscenetransition/ActivitySceneTransitionBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/activitytasks/DocumentCentricApps/gradle/wrapper/gradle-wrapper.properties b/ui/activitytasks/DocumentCentricApps/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/activitytasks/DocumentCentricApps/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/activitytasks/DocumentCentricApps/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/gradle/wrapper/gradle-wrapper.properties b/ui/activitytasks/DocumentCentricRelinquishIdentity/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/activitytasks/DocumentCentricRelinquishIdentity/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/fonts/DownloadableFonts/build.gradle b/ui/fonts/DownloadableFonts/build.gradle
index 1144b33..3fa2842 100644
--- a/ui/fonts/DownloadableFonts/build.gradle
+++ b/ui/fonts/DownloadableFonts/build.gradle
@@ -5,7 +5,7 @@
         google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.0.0-alpha9'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/ui/fonts/DownloadableFonts/gradle/wrapper/gradle-wrapper.properties b/ui/fonts/DownloadableFonts/gradle/wrapper/gradle-wrapper.properties
index fa419a3..716f641 100644
--- a/ui/fonts/DownloadableFonts/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/fonts/DownloadableFonts/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/ui/fonts/DownloadableFonts/kotlinApp/build.gradle b/ui/fonts/DownloadableFonts/kotlinApp/build.gradle
index 138d54e..7b7482b 100644
--- a/ui/fonts/DownloadableFonts/kotlinApp/build.gradle
+++ b/ui/fonts/DownloadableFonts/kotlinApp/build.gradle
@@ -6,7 +6,7 @@
         google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.0.0-alpha9'
+        classpath 'com.android.tools.build:gradle:3.0.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
diff --git a/ui/graphics/DisplayingBitmaps/gradle/wrapper/gradle-wrapper.properties b/ui/graphics/DisplayingBitmaps/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/graphics/DisplayingBitmaps/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/graphics/DisplayingBitmaps/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/graphics/PdfRendererBasic/gradle/wrapper/gradle-wrapper.properties b/ui/graphics/PdfRendererBasic/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/graphics/PdfRendererBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/graphics/PdfRendererBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/.google/packaging.yaml b/ui/graphics/PdfRendererBasic/kotlinApp/.google/packaging.yaml
new file mode 100644
index 0000000..764745c
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/.google/packaging.yaml
@@ -0,0 +1,17 @@
+
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [UI, Graphics]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-PdfRendererBasic
+level:        BEGINNER
+icon:         screenshots/icon-web.png
+apiRefs:
+    - android:android.graphics.pdf.PdfRenderer
+license: apache2
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/build.gradle b/ui/graphics/PdfRendererBasic/kotlinApp/Application/build.gradle
new file mode 100644
index 0000000..19b947f
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/build.gradle
@@ -0,0 +1,35 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion rootProject.ext.compileSdkVersion
+    defaultConfig {
+        applicationId "com.example.android.pdfrendererbasic"
+        minSdkVersion rootProject.ext.minSdkVersion
+        targetSdkVersion rootProject.ext.targetSdkVersion
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:$rootProject.ext.supportLibVersion"
+    implementation "com.android.support:support-v4:$rootProject.ext.supportLibVersion"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
+
+    // Testing dependencies
+    androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$rootProject.ext.espressoVersion"
+    androidTestImplementation "com.android.support.test.espresso:espresso-core:$rootProject.ext.espressoVersion"
+    androidTestCompile "com.android.support:support-annotations:$rootProject.ext.supportLibVersion"
+    androidTestCompile "com.android.support.test:runner:$rootProject.ext.supportTestVersion"
+    androidTestCompile "com.android.support.test:rules:$rootProject.ext.supportTestVersion"
+    testImplementation "junit:junit:$rootProject.ext.junitVersion"
+}
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragmentTests.kt b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragmentTests.kt
new file mode 100644
index 0000000..b2abc69
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragmentTests.kt
@@ -0,0 +1,125 @@
+/*
+ * 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 com.example.android.pdfrendererbasic
+
+import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+import android.support.test.espresso.Espresso.onView
+import android.support.test.espresso.action.ViewActions.click
+import android.support.test.espresso.matcher.ViewMatchers.withId
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import android.widget.Button
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for PdfRendererBasic sample.
+ */
+@RunWith(AndroidJUnit4::class)
+class PdfRendererBasicFragmentTests {
+
+    private lateinit var fragment: PdfRendererBasicFragment
+    private lateinit var btnPrevious: Button
+    private lateinit var btnNext: Button
+
+    @Rule @JvmField
+    val activityTestRule = ActivityTestRule(MainActivity::class.java)
+
+    @Before fun before() {
+        activityTestRule.activity.supportFragmentManager.beginTransaction()
+        fragment = activityTestRule.activity.supportFragmentManager
+                .findFragmentByTag(FRAGMENT_PDF_RENDERER_BASIC) as PdfRendererBasicFragment
+    }
+
+    @Test fun testActivityTitle() {
+        // The title of the activity should be "PdfRendererBasic (1/10)" at first
+        val expectedActivityTitle = activityTestRule.activity.getString(
+                R.string.app_name_with_index, 1, fragment.getPageCount())
+        assertEquals(expectedActivityTitle, activityTestRule.activity.title)
+    }
+
+    @Test fun testButtons_previousDisabledAtFirst() {
+        setUpButtons()
+        // Check that the previous button is disabled at first
+        assertFalse(btnPrevious.isEnabled)
+        // The next button should be enabled
+        assertTrue(btnNext.isEnabled)
+    }
+
+    @Test fun testButtons_bothEnabledInMiddle() {
+        setUpButtons()
+        turnPages(1)
+        // Two buttons should be both enabled
+        assertTrue(btnPrevious.isEnabled)
+        assertTrue(btnNext.isEnabled)
+    }
+
+    @Test fun testButtons_nextDisabledLastPage() {
+        setUpButtons()
+        val pageCount = fragment.getPageCount()
+        // Click till it reaches the last page
+        turnPages(pageCount - 1)
+        // Check the page count
+        val expectedActivityTitle = activityTestRule.activity.getString(
+                R.string.app_name_with_index, pageCount, pageCount)
+        assertEquals(expectedActivityTitle, activityTestRule.activity.title)
+        // The previous button should be enabled
+        assertTrue(btnPrevious.isEnabled)
+        // Check that the next button is disabled
+        assertFalse(btnNext.isEnabled)
+    }
+
+    @Test fun testOrientationChangePreserveState() {
+        activityTestRule.activity.requestedOrientation = SCREEN_ORIENTATION_PORTRAIT
+        setUpButtons()
+        turnPages(1)
+        val pageCount = fragment.getPageCount()
+        val expectedActivityTitle = activityTestRule.activity
+                .getString(R.string.app_name_with_index, 2, pageCount)
+        assertEquals(expectedActivityTitle, activityTestRule.activity.title)
+        activityTestRule.activity.requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE
+        // Check that the title is the same after orientation change
+        assertEquals(expectedActivityTitle, activityTestRule.activity.title)
+    }
+
+    /**
+     * Prepares references to the buttons "Previous" and "Next".
+     */
+    private fun setUpButtons() {
+        val view = fragment.view ?: return
+        btnPrevious = view.findViewById(R.id.previous)
+        btnNext = view.findViewById(R.id.next)
+    }
+
+    /**
+     * Click the "Next" button to turn the pages.
+     *
+     * @param count The number of times to turn pages.
+     */
+    private fun turnPages(count: Int) {
+        for (i in 0 until count) {
+            onView(withId(R.id.next)).perform(click())
+        }
+    }
+
+}
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/AndroidManifest.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..de585c9
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.pdfrendererbasic">
+
+    <application android:allowBackup="false"
+        android:label="@string/app_name"
+        android:icon="@mipmap/ic_launcher"
+        android:theme="@style/Theme.PdfRendererBasic">
+
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+
+</manifest>
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/assets/sample.pdf b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/assets/sample.pdf
new file mode 100644
index 0000000..73f68b1
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/assets/sample.pdf
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.kt b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.kt
new file mode 100644
index 0000000..1d253bd
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.kt
@@ -0,0 +1,58 @@
+/*
+ * 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 com.example.android.pdfrendererbasic
+
+import android.app.AlertDialog
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.Menu
+import android.view.MenuItem
+
+val FRAGMENT_PDF_RENDERER_BASIC = "pdf_renderer_basic"
+
+class MainActivity : AppCompatActivity() {
+
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main_real)
+        if (savedInstanceState == null) {
+            supportFragmentManager.beginTransaction()
+                    .add(R.id.container, PdfRendererBasicFragment(), FRAGMENT_PDF_RENDERER_BASIC)
+                    .commit()
+        }
+    }
+
+    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+        menuInflater.inflate(R.menu.main, menu)
+        return true
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        return when (item.itemId) {
+            R.id.action_info -> {
+                AlertDialog.Builder(this)
+                        .setMessage(R.string.intro_message)
+                        .setPositiveButton(android.R.string.ok, null)
+                        .show()
+                return true
+            }
+            else -> super.onOptionsItemSelected(item)
+        }
+    }
+
+}
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.kt b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.kt
new file mode 100644
index 0000000..89e1cfd
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.kt
@@ -0,0 +1,237 @@
+/*
+ * 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 com.example.android.pdfrendererbasic
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Bitmap.createBitmap
+import android.graphics.pdf.PdfRenderer
+import android.os.Bundle
+import android.os.ParcelFileDescriptor
+import android.support.v4.app.Fragment
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.ImageView
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+
+/**
+ * This fragment has a big [ImageView] that shows PDF pages, and 2 [Button]s to move between pages.
+ * We use a [PdfRenderer] to render PDF pages as [Bitmap]s.
+ */
+class PdfRendererBasicFragment : Fragment(), View.OnClickListener {
+
+    /**
+     * The filename of the PDF.
+     */
+    private val FILENAME = "sample.pdf"
+
+    /**
+     * Key string for saving the state of current page index.
+     */
+    private val STATE_CURRENT_PAGE_INDEX = "current_page_index"
+
+    /**
+     * String for logging.
+     */
+    private val TAG = "PdfRendererBasicFragment"
+
+    /**
+     * The initial page index of the PDF.
+     */
+    private val INITIAL_PAGE_INDEX = 0
+
+    /**
+     * File descriptor of the PDF.
+     */
+    private lateinit var fileDescriptor: ParcelFileDescriptor
+
+    /**
+     * [PdfRenderer] to render the PDF.
+     */
+    private lateinit var pdfRenderer: PdfRenderer
+
+    /**
+     * Page that is currently shown on the screen.
+     */
+    private lateinit var currentPage: PdfRenderer.Page
+
+    /**
+     * [ImageView] that shows a PDF page as a [Bitmap].
+     */
+    private lateinit var imageView: ImageView
+
+    /**
+     * [Button] to move to the previous page.
+     */
+    private lateinit var btnPrevious: Button
+
+    /**
+     * [Button] to move to the next page.
+     */
+    private lateinit var btnNext: Button
+
+    /**
+     * PDF page index.
+     */
+    private var pageIndex: Int = INITIAL_PAGE_INDEX
+
+    override fun onCreateView(
+            inflater: LayoutInflater,
+            container: ViewGroup?,
+            savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        imageView = view.findViewById(R.id.image)
+        btnPrevious = view.findViewById<Button>(R.id.previous).also { it.setOnClickListener(this) }
+        btnNext = view.findViewById<Button>(R.id.next).also { it.setOnClickListener(this)}
+
+        // If there is a savedInstanceState (screen orientations, etc.), we restore the page index.
+        if (savedInstanceState != null) {
+            pageIndex = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, INITIAL_PAGE_INDEX)
+        } else {
+            pageIndex = INITIAL_PAGE_INDEX
+        }
+    }
+
+    override fun onStart() {
+        super.onStart()
+        try {
+            openRenderer(activity)
+            showPage(pageIndex)
+        } catch (e: IOException) {
+            Log.d(TAG, e.toString())
+        }
+    }
+
+    override fun onStop() {
+        try {
+            closeRenderer()
+        } catch (e: IOException) {
+            Log.d(TAG, e.toString())
+        }
+        super.onStop()
+    }
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        outState.putInt(STATE_CURRENT_PAGE_INDEX, currentPage.index)
+        super.onSaveInstanceState(outState)
+    }
+
+    /**
+     * Sets up a [PdfRenderer] and related resources.
+     */
+    @Throws(IOException::class)
+    private fun openRenderer(context: Context?) {
+        if (context == null) return
+
+        // In this sample, we read a PDF from the assets directory.
+        val file = File(context.cacheDir, FILENAME)
+        if (!file.exists()) {
+            // Since PdfRenderer cannot handle the compressed asset file directly, we copy it into
+            // the cache directory.
+            val asset = context.assets.open(FILENAME)
+            val output = FileOutputStream(file)
+            val buffer = ByteArray(1024)
+            var size = asset.read(buffer)
+            while (size != -1) {
+                output.write(buffer, 0, size)
+                size = asset.read(buffer)
+            }
+            asset.close()
+            output.close()
+        }
+        fileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
+        // This is the PdfRenderer we use to render the PDF.
+        pdfRenderer = PdfRenderer(fileDescriptor)
+        currentPage = pdfRenderer.openPage(pageIndex)
+    }
+
+    /**
+     * Closes the [PdfRenderer] and related resources.
+     *
+     * @throws IOException When the PDF file cannot be closed.
+     */
+    @Throws(IOException::class)
+    private fun closeRenderer() {
+        currentPage.close()
+        pdfRenderer.close()
+        fileDescriptor.close()
+    }
+
+    /**
+     * Shows the specified page of PDF to the screen.
+     *
+     * @param index The page index.
+     */
+    private fun showPage(index: Int) {
+        if (pdfRenderer.pageCount <= index) return
+
+        // Make sure to close the current page before opening another one.
+        currentPage.close()
+        // Use `openPage` to open a specific page in PDF.
+        currentPage = pdfRenderer.openPage(index)
+        // Important: the destination bitmap must be ARGB (not RGB).
+        val bitmap = createBitmap(currentPage.width, currentPage.height, Bitmap.Config.ARGB_8888)
+        // Here, we render the page onto the Bitmap.
+        // To render a portion of the page, use the second and third parameter. Pass nulls to get
+        // the default result.
+        // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
+        currentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
+        // We are ready to show the Bitmap to user.
+        imageView.setImageBitmap(bitmap)
+        updateUi()
+    }
+
+    /**
+     * Updates the state of 2 control buttons in response to the current page index.
+     */
+    private fun updateUi() {
+        val index = currentPage.index
+        val pageCount = pdfRenderer.pageCount
+        btnPrevious.isEnabled = (0 != index)
+        btnNext.isEnabled = (index + 1 < pageCount)
+        activity?.title = getString(R.string.app_name_with_index, index + 1, pageCount)
+    }
+
+    /**
+     * Returns the page count of of the PDF.
+     */
+    fun getPageCount() = pdfRenderer.pageCount
+
+    override fun onClick(view: View) {
+        when (view.id) {
+            R.id.previous -> {
+                // Move to the previous page/
+                showPage(currentPage.index - 1)
+            }
+            R.id.next -> {
+                // Move to the next page.
+                showPage(currentPage.index + 1)
+            }
+        }
+    }
+
+}
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/drawable/ic_info.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/drawable/ic_info.xml
new file mode 100644
index 0000000..d33f690
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/drawable/ic_info.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
+</vector>
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/activity_main_real.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/activity_main_real.xml
new file mode 100644
index 0000000..5d130ff
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/activity_main_real.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity"
+    tools:ignore="MergeRootFrame" />
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml
new file mode 100644
index 0000000..aa8a9e1
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+<LinearLayout 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"
+    android:orientation="vertical"
+    tools:context=".PdfRendererBasicFragment">
+
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:background="@android:color/white"
+        android:scaleType="fitCenter"
+        android:contentDescription="@null"/>
+
+    <LinearLayout
+        style="?android:attr/buttonBarStyle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:measureWithLargestChild="true"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/previous"
+            style="?android:attr/buttonBarButtonStyle"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/previous" />
+
+        <Button
+            android:id="@+id/next"
+            style="?android:attr/buttonBarButtonStyle"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/next" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/menu/main.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/menu/main.xml
new file mode 100644
index 0000000..15effa2
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/menu/main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item
+        android:id="@+id/action_info"
+        android:icon="@drawable/ic_info"
+        android:title="@string/info"
+        app:showAsAction="ifRoom"/>
+
+</menu>
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-hdpi/ic_launcher.png b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..1c8ac30
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-mdpi/ic_launcher.png b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..b3a72f8
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-xhdpi/ic_launcher.png b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..cd3a7b2
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfabc63
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..da39c01
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/strings.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..55f04f9
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+
+    <string name="app_name">PdfRendererBasic</string>
+    <string name="app_name_with_index">PdfRendererBasic (%1$d/%2$d)</string>
+    <string name="info">Info</string>
+    <string name="previous">Previous</string>
+    <string name="next">Next</string>
+    <string name="intro_message">
+        <![CDATA[
+
+
+            This sample demonstrates how to use PdfRenderer to display PDF documents on the screen.
+
+
+        ]]>
+    </string>
+</resources>
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/styles.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..a41be2b
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <style name="Theme.PdfRendererBasic" parent="Theme.AppCompat.Light.DarkActionBar">
+        <item name="colorPrimary">#F44336</item>
+        <item name="colorPrimaryDark">#D32F2F</item>
+        <item name="colorAccent">#00BCD4</item>
+    </style>
+</resources>
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/tests/AndroidManifest.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..54829c7
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/tests/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2014 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest
+    package="com.example.android.pdfrendererbasic.tests"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+    <!-- We add an application tag here just so that we can indicate that
+         this package needs to link against the android.test library,
+         which is needed when building test cases. -->
+    <application>
+        <uses-library android:name="android.test.runner"/>
+    </application>
+
+    <!--
+    Specifies the instrumentation test runner used to run the tests.
+    -->
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:label="Tests for com.example.android.pdfrendererbasic"
+        android:targetPackage="com.example.android.pdfrendererbasic"/>
+
+</manifest>
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/CONTRIBUTING.md b/ui/graphics/PdfRendererBasic/kotlinApp/CONTRIBUTING.md
new file mode 100644
index 0000000..faa8b5c
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/CONTRIBUTING.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual CLA]
+    (https://cla.developers.google.com).
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA]
+    (https://cla.developers.google.com).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+   Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+   you are contributing. Refer to the
+   [Android Code Style Guide]
+   (https://source.android.com/source/code-style.html) for the
+   recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/LICENSE b/ui/graphics/PdfRendererBasic/kotlinApp/LICENSE
new file mode 100644
index 0000000..4f22946
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/LICENSE
@@ -0,0 +1,647 @@
+Apache License
+--------------
+
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav 
+and *.ogg) are licensed under the CC-BY-NC license. All other files are 
+licensed under the Apache 2 license.
+
+CC-BY-NC License
+----------------
+
+Attribution-NonCommercial-ShareAlike 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+     Considerations for licensors: Our public licenses are
+     intended for use by those authorized to give the public
+     permission to use material in ways otherwise restricted by
+     copyright and certain other rights. Our licenses are
+     irrevocable. Licensors should read and understand the terms
+     and conditions of the license they choose before applying it.
+     Licensors should also secure all rights necessary before
+     applying our licenses so that the public can reuse the
+     material as expected. Licensors should clearly mark any
+     material not subject to the license. This includes other CC-
+     licensed material, or material used under an exception or
+     limitation to copyright. More considerations for licensors:
+	wiki.creativecommons.org/Considerations_for_licensors
+
+     Considerations for the public: By using one of our public
+     licenses, a licensor grants the public permission to use the
+     licensed material under specified terms and conditions. If
+     the licensor's permission is not necessary for any reason--for
+     example, because of any applicable exception or limitation to
+     copyright--then that use is not regulated by the license. Our
+     licenses grant only permissions under copyright and certain
+     other rights that a licensor has authority to grant. Use of
+     the licensed material may still be restricted for other
+     reasons, including because others have copyright or other
+     rights in the material. A licensor may make special requests,
+     such as asking that all changes be marked or described.
+     Although not required by our licenses, you are encouraged to
+     respect those requests where reasonable. More_considerations
+     for the public: 
+	wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
+Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-NonCommercial-ShareAlike 4.0 International Public License
+("Public License"). To the extent this Public License may be
+interpreted as a contract, You are granted the Licensed Rights in
+consideration of Your acceptance of these terms and conditions, and the
+Licensor grants You such rights in consideration of benefits the
+Licensor receives from making the Licensed Material available under
+these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+  a. Adapted Material means material subject to Copyright and Similar
+     Rights that is derived from or based upon the Licensed Material
+     and in which the Licensed Material is translated, altered,
+     arranged, transformed, or otherwise modified in a manner requiring
+     permission under the Copyright and Similar Rights held by the
+     Licensor. For purposes of this Public License, where the Licensed
+     Material is a musical work, performance, or sound recording,
+     Adapted Material is always produced where the Licensed Material is
+     synched in timed relation with a moving image.
+
+  b. Adapter's License means the license You apply to Your Copyright
+     and Similar Rights in Your contributions to Adapted Material in
+     accordance with the terms and conditions of this Public License.
+
+  c. BY-NC-SA Compatible License means a license listed at
+     creativecommons.org/compatiblelicenses, approved by Creative
+     Commons as essentially the equivalent of this Public License.
+
+  d. Copyright and Similar Rights means copyright and/or similar rights
+     closely related to copyright including, without limitation,
+     performance, broadcast, sound recording, and Sui Generis Database
+     Rights, without regard to how the rights are labeled or
+     categorized. For purposes of this Public License, the rights
+     specified in Section 2(b)(1)-(2) are not Copyright and Similar
+     Rights.
+
+  e. Effective Technological Measures means those measures that, in the
+     absence of proper authority, may not be circumvented under laws
+     fulfilling obligations under Article 11 of the WIPO Copyright
+     Treaty adopted on December 20, 1996, and/or similar international
+     agreements.
+
+  f. Exceptions and Limitations means fair use, fair dealing, and/or
+     any other exception or limitation to Copyright and Similar Rights
+     that applies to Your use of the Licensed Material.
+
+  g. License Elements means the license attributes listed in the name
+     of a Creative Commons Public License. The License Elements of this
+     Public License are Attribution, NonCommercial, and ShareAlike.
+
+  h. Licensed Material means the artistic or literary work, database,
+     or other material to which the Licensor applied this Public
+     License.
+
+  i. Licensed Rights means the rights granted to You subject to the
+     terms and conditions of this Public License, which are limited to
+     all Copyright and Similar Rights that apply to Your use of the
+     Licensed Material and that the Licensor has authority to license.
+
+  j. Licensor means the individual(s) or entity(ies) granting rights
+     under this Public License.
+
+  k. NonCommercial means not primarily intended for or directed towards
+     commercial advantage or monetary compensation. For purposes of
+     this Public License, the exchange of the Licensed Material for
+     other material subject to Copyright and Similar Rights by digital
+     file-sharing or similar means is NonCommercial provided there is
+     no payment of monetary compensation in connection with the
+     exchange.
+
+  l. Share means to provide material to the public by any means or
+     process that requires permission under the Licensed Rights, such
+     as reproduction, public display, public performance, distribution,
+     dissemination, communication, or importation, and to make material
+     available to the public including in ways that members of the
+     public may access the material from a place and at a time
+     individually chosen by them.
+
+  m. Sui Generis Database Rights means rights other than copyright
+     resulting from Directive 96/9/EC of the European Parliament and of
+     the Council of 11 March 1996 on the legal protection of databases,
+     as amended and/or succeeded, as well as other essentially
+     equivalent rights anywhere in the world.
+
+  n. You means the individual or entity exercising the Licensed Rights
+     under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+  a. License grant.
+
+       1. Subject to the terms and conditions of this Public License,
+          the Licensor hereby grants You a worldwide, royalty-free,
+          non-sublicensable, non-exclusive, irrevocable license to
+          exercise the Licensed Rights in the Licensed Material to:
+
+            a. reproduce and Share the Licensed Material, in whole or
+               in part, for NonCommercial purposes only; and
+
+            b. produce, reproduce, and Share Adapted Material for
+               NonCommercial purposes only.
+
+       2. Exceptions and Limitations. For the avoidance of doubt, where
+          Exceptions and Limitations apply to Your use, this Public
+          License does not apply, and You do not need to comply with
+          its terms and conditions.
+
+       3. Term. The term of this Public License is specified in Section
+          6(a).
+
+       4. Media and formats; technical modifications allowed. The
+          Licensor authorizes You to exercise the Licensed Rights in
+          all media and formats whether now known or hereafter created,
+          and to make technical modifications necessary to do so. The
+          Licensor waives and/or agrees not to assert any right or
+          authority to forbid You from making technical modifications
+          necessary to exercise the Licensed Rights, including
+          technical modifications necessary to circumvent Effective
+          Technological Measures. For purposes of this Public License,
+          simply making modifications authorized by this Section 2(a)
+          (4) never produces Adapted Material.
+
+       5. Downstream recipients.
+
+            a. Offer from the Licensor -- Licensed Material. Every
+               recipient of the Licensed Material automatically
+               receives an offer from the Licensor to exercise the
+               Licensed Rights under the terms and conditions of this
+               Public License.
+
+            b. Additional offer from the Licensor -- Adapted Material.
+               Every recipient of Adapted Material from You
+               automatically receives an offer from the Licensor to
+               exercise the Licensed Rights in the Adapted Material
+               under the conditions of the Adapter's License You apply.
+
+            c. No downstream restrictions. You may not offer or impose
+               any additional or different terms or conditions on, or
+               apply any Effective Technological Measures to, the
+               Licensed Material if doing so restricts exercise of the
+               Licensed Rights by any recipient of the Licensed
+               Material.
+
+       6. No endorsement. Nothing in this Public License constitutes or
+          may be construed as permission to assert or imply that You
+          are, or that Your use of the Licensed Material is, connected
+          with, or sponsored, endorsed, or granted official status by,
+          the Licensor or others designated to receive attribution as
+          provided in Section 3(a)(1)(A)(i).
+
+  b. Other rights.
+
+       1. Moral rights, such as the right of integrity, are not
+          licensed under this Public License, nor are publicity,
+          privacy, and/or other similar personality rights; however, to
+          the extent possible, the Licensor waives and/or agrees not to
+          assert any such rights held by the Licensor to the limited
+          extent necessary to allow You to exercise the Licensed
+          Rights, but not otherwise.
+
+       2. Patent and trademark rights are not licensed under this
+          Public License.
+
+       3. To the extent possible, the Licensor waives any right to
+          collect royalties from You for the exercise of the Licensed
+          Rights, whether directly or through a collecting society
+          under any voluntary or waivable statutory or compulsory
+          licensing scheme. In all other cases the Licensor expressly
+          reserves any right to collect such royalties, including when
+          the Licensed Material is used other than for NonCommercial
+          purposes.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+  a. Attribution.
+
+       1. If You Share the Licensed Material (including in modified
+          form), You must:
+
+            a. retain the following if it is supplied by the Licensor
+               with the Licensed Material:
+
+                 i. identification of the creator(s) of the Licensed
+                    Material and any others designated to receive
+                    attribution, in any reasonable manner requested by
+                    the Licensor (including by pseudonym if
+                    designated);
+
+                ii. a copyright notice;
+
+               iii. a notice that refers to this Public License;
+
+                iv. a notice that refers to the disclaimer of
+                    warranties;
+
+                 v. a URI or hyperlink to the Licensed Material to the
+                    extent reasonably practicable;
+
+            b. indicate if You modified the Licensed Material and
+               retain an indication of any previous modifications; and
+
+            c. indicate the Licensed Material is licensed under this
+               Public License, and include the text of, or the URI or
+               hyperlink to, this Public License.
+
+       2. You may satisfy the conditions in Section 3(a)(1) in any
+          reasonable manner based on the medium, means, and context in
+          which You Share the Licensed Material. For example, it may be
+          reasonable to satisfy the conditions by providing a URI or
+          hyperlink to a resource that includes the required
+          information.
+       3. If requested by the Licensor, You must remove any of the
+          information required by Section 3(a)(1)(A) to the extent
+          reasonably practicable.
+
+  b. ShareAlike.
+
+     In addition to the conditions in Section 3(a), if You Share
+     Adapted Material You produce, the following conditions also apply.
+
+       1. The Adapter's License You apply must be a Creative Commons
+          license with the same License Elements, this version or
+          later, or a BY-NC-SA Compatible License.
+
+       2. You must include the text of, or the URI or hyperlink to, the
+          Adapter's License You apply. You may satisfy this condition
+          in any reasonable manner based on the medium, means, and
+          context in which You Share Adapted Material.
+
+       3. You may not offer or impose any additional or different terms
+          or conditions on, or apply any Effective Technological
+          Measures to, Adapted Material that restrict exercise of the
+          rights granted under the Adapter's License You apply.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+     to extract, reuse, reproduce, and Share all or a substantial
+     portion of the contents of the database for NonCommercial purposes
+     only;
+
+  b. if You include all or a substantial portion of the database
+     contents in a database in which You have Sui Generis Database
+     Rights, then the database in which You have Sui Generis Database
+     Rights (but not its individual contents) is Adapted Material,
+     including for purposes of Section 3(b); and
+
+  c. You must comply with the conditions in Section 3(a) if You Share
+     all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+  c. The disclaimer of warranties and limitation of liability provided
+     above shall be interpreted in a manner that, to the extent
+     possible, most closely approximates an absolute disclaimer and
+     waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+  a. This Public License applies for the term of the Copyright and
+     Similar Rights licensed here. However, if You fail to comply with
+     this Public License, then Your rights under this Public License
+     terminate automatically.
+
+  b. Where Your right to use the Licensed Material has terminated under
+     Section 6(a), it reinstates:
+
+       1. automatically as of the date the violation is cured, provided
+          it is cured within 30 days of Your discovery of the
+          violation; or
+
+       2. upon express reinstatement by the Licensor.
+
+     For the avoidance of doubt, this Section 6(b) does not affect any
+     right the Licensor may have to seek remedies for Your violations
+     of this Public License.
+
+  c. For the avoidance of doubt, the Licensor may also offer the
+     Licensed Material under separate terms or conditions or stop
+     distributing the Licensed Material at any time; however, doing so
+     will not terminate this Public License.
+
+  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+     License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+  a. The Licensor shall not be bound by any additional or different
+     terms or conditions communicated by You unless expressly agreed.
+
+  b. Any arrangements, understandings, or agreements regarding the
+     Licensed Material not stated herein are separate from and
+     independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+  a. For the avoidance of doubt, this Public License does not, and
+     shall not be interpreted to, reduce, limit, restrict, or impose
+     conditions on any use of the Licensed Material that could lawfully
+     be made without permission under this Public License.
+
+  b. To the extent possible, if any provision of this Public License is
+     deemed unenforceable, it shall be automatically reformed to the
+     minimum extent necessary to make it enforceable. If the provision
+     cannot be reformed, it shall be severed from this Public License
+     without affecting the enforceability of the remaining terms and
+     conditions.
+
+  c. No term or condition of this Public License will be waived and no
+     failure to comply consented to unless expressly agreed to by the
+     Licensor.
+
+  d. Nothing in this Public License constitutes or may be interpreted
+     as a limitation upon, or waiver of, any privileges and immunities
+     that apply to the Licensor or You, including from the legal
+     processes of any jurisdiction or authority.
+
+=======================================================================
+
+Creative Commons is not a party to its public licenses.
+Notwithstanding, Creative Commons may elect to apply one of its public
+licenses to material it publishes and in those instances will be
+considered the "Licensor." Except for the limited purpose of indicating
+that material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the public
+licenses.
+
+Creative Commons may be contacted at creativecommons.org.
+
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/README.md b/ui/graphics/PdfRendererBasic/kotlinApp/README.md
new file mode 100644
index 0000000..e99bce6
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/README.md
@@ -0,0 +1,75 @@
+
+Android PdfRendererBasic Sample (Kotlin)
+========================================
+
+This sample demonstrates how to display PDF document on screen using
+the PdfRenderer introduced in Android 5.0 Lollipop.
+
+Introduction
+------------
+
+You can now render PDF document pages into bitmap images for printing by using
+the new [PdfRenderer][1] class. You must specify a [ParcelFileDescriptor][2]
+that is seekable (that is, the content can be randomly accessed) on which the
+system writes the the printable content. Your app can obtain a page for
+rendering with [openPage()][3], then call [render()][4] to turn the opened
+[PdfRenderer.Page][5] into a bitmap.
+
+This sample loads the PDF from assets. Contents of assets are compressed by
+default, and the PdfRenderer class cannot open it. In this sample, we work
+around this by copying the file into the cache directory.
+
+[1]: https://developer.android.com/reference/android/graphics/pdf/PdfRenderer.html
+[2]: https://developer.android.com/reference/android/os/ParcelFileDescriptor.html
+[3]: https://developer.android.com/reference/android/graphics/pdf/PdfRenderer.html#openPage(int)
+[4]: https://developer.android.com/reference/android/graphics/pdf/PdfRenderer.Page.html#render(android.graphics.Bitmap,%20android.graphics.Rect,%20android.graphics.Matrix,%20int)
+[5]: https://developer.android.com/reference/android/graphics/pdf/PdfRenderer.Page.html
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Support Repository
+
+Screenshots
+-------------
+
+<img src="screenshots/main.png" height="400" alt="Screenshot"/>
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-PdfRendererBasic
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2017 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/build.gradle b/ui/graphics/PdfRendererBasic/kotlinApp/build.gradle
new file mode 100644
index 0000000..c1ee1e5
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/build.gradle
@@ -0,0 +1,32 @@
+buildscript {
+    ext {
+        compileSdkVersion = 27
+        minSdkVersion = 24
+        targetSdkVersion = 27
+
+        espressoVersion = '3.0.1'
+        junitVersion = '4.12'
+        kotlinVersion = '1.2.0'
+        supportLibVersion = '27.0.2'
+        supportTestVersion = '1.0.1'
+    }
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/ui/graphics/PdfRendererBasic/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/ui/graphics/PdfRendererBasic/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..4867119
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Dec 11 10:28:08 PST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
\ No newline at end of file
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/gradlew b/ui/graphics/PdfRendererBasic/kotlinApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/gradlew.bat b/ui/graphics/PdfRendererBasic/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/screenshots/icon-web.png b/ui/graphics/PdfRendererBasic/kotlinApp/screenshots/icon-web.png
new file mode 100755
index 0000000..a80c352
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/screenshots/icon-web.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/screenshots/main.png b/ui/graphics/PdfRendererBasic/kotlinApp/screenshots/main.png
new file mode 100644
index 0000000..faff891
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/screenshots/main.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/settings.gradle b/ui/graphics/PdfRendererBasic/kotlinApp/settings.gradle
new file mode 100644
index 0000000..9464a35
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'Application'
diff --git a/ui/holo/BorderlessButtons/gradle/wrapper/gradle-wrapper.properties b/ui/holo/BorderlessButtons/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/holo/BorderlessButtons/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/holo/BorderlessButtons/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/lists/CustomChoiceList/gradle/wrapper/gradle-wrapper.properties b/ui/lists/CustomChoiceList/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/lists/CustomChoiceList/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/lists/CustomChoiceList/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/text/.google/packaging.yaml b/ui/text/.google/packaging.yaml
new file mode 100644
index 0000000..11e27f4
--- /dev/null
+++ b/ui/text/.google/packaging.yaml
@@ -0,0 +1,45 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+# Values: {DRAFT | PUBLISHED | INTERNAL | DEPRECATED | SUPERCEDED}
+status:       PUBLISHED
+
+# Optional, put additional explanation here for DEPRECATED or SUPERCEDED.
+# statusNote:
+
+# See http://go/sample-categories
+technologies: [Android]
+categories:   [Getting Started, UI, Text]
+languages:    [Java]
+solutions:    [Mobile]
+
+# May be omitted if unpublished
+github:       google/android-text
+
+# Values: BEGINNER | INTERMEDIATE | ADVANCED | EXPERT
+level:        BEGINNER
+
+# Dimensions: 512x512, PNG fomrat
+icon: screenshots/icon_web.png
+
+# List of APIs that this sample should be listed under. Use authoritive,
+# names that are unique for the product in question. Examples:
+#
+# Android -    android:<class-name>
+# App Engine - gae-java:<class name>
+#              gae-python:<package>
+# Web Services - ws:<name of API from Cloud Console>
+apiRefs:
+    - android:android.text.SpannableStringBuilder
+    - android:android.text.Spanned
+    - android:android.text.SpannedString
+    - android:android.text.style.StyleSpan
+    - android:android.text.style.RelativeSizeSpan
+    - android:android.text.style.MetricAffectingSpan
+
+
+# Default: apache2. May be omitted for most samples.
+# Alternatives: apache2-android (for AOSP)
+license: apache2
diff --git a/ui/text/CONTRIBUTING.md b/ui/text/CONTRIBUTING.md
new file mode 100644
index 0000000..8ddb52d
--- /dev/null
+++ b/ui/text/CONTRIBUTING.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual CLA]
+    (https://developers.google.com/open-source/cla/individual).
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA]
+    (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+   Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+   you are contributing. Refer to the
+   [Google Cloud Platform Samples Style Guide]
+   (https://github.com/GoogleCloudPlatform/Template/wiki/style.html) for the
+   recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/ui/text/LICENSE b/ui/text/LICENSE
new file mode 100644
index 0000000..4f22946
--- /dev/null
+++ b/ui/text/LICENSE
@@ -0,0 +1,647 @@
+Apache License
+--------------
+
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav 
+and *.ogg) are licensed under the CC-BY-NC license. All other files are 
+licensed under the Apache 2 license.
+
+CC-BY-NC License
+----------------
+
+Attribution-NonCommercial-ShareAlike 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+     Considerations for licensors: Our public licenses are
+     intended for use by those authorized to give the public
+     permission to use material in ways otherwise restricted by
+     copyright and certain other rights. Our licenses are
+     irrevocable. Licensors should read and understand the terms
+     and conditions of the license they choose before applying it.
+     Licensors should also secure all rights necessary before
+     applying our licenses so that the public can reuse the
+     material as expected. Licensors should clearly mark any
+     material not subject to the license. This includes other CC-
+     licensed material, or material used under an exception or
+     limitation to copyright. More considerations for licensors:
+	wiki.creativecommons.org/Considerations_for_licensors
+
+     Considerations for the public: By using one of our public
+     licenses, a licensor grants the public permission to use the
+     licensed material under specified terms and conditions. If
+     the licensor's permission is not necessary for any reason--for
+     example, because of any applicable exception or limitation to
+     copyright--then that use is not regulated by the license. Our
+     licenses grant only permissions under copyright and certain
+     other rights that a licensor has authority to grant. Use of
+     the licensed material may still be restricted for other
+     reasons, including because others have copyright or other
+     rights in the material. A licensor may make special requests,
+     such as asking that all changes be marked or described.
+     Although not required by our licenses, you are encouraged to
+     respect those requests where reasonable. More_considerations
+     for the public: 
+	wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
+Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-NonCommercial-ShareAlike 4.0 International Public License
+("Public License"). To the extent this Public License may be
+interpreted as a contract, You are granted the Licensed Rights in
+consideration of Your acceptance of these terms and conditions, and the
+Licensor grants You such rights in consideration of benefits the
+Licensor receives from making the Licensed Material available under
+these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+  a. Adapted Material means material subject to Copyright and Similar
+     Rights that is derived from or based upon the Licensed Material
+     and in which the Licensed Material is translated, altered,
+     arranged, transformed, or otherwise modified in a manner requiring
+     permission under the Copyright and Similar Rights held by the
+     Licensor. For purposes of this Public License, where the Licensed
+     Material is a musical work, performance, or sound recording,
+     Adapted Material is always produced where the Licensed Material is
+     synched in timed relation with a moving image.
+
+  b. Adapter's License means the license You apply to Your Copyright
+     and Similar Rights in Your contributions to Adapted Material in
+     accordance with the terms and conditions of this Public License.
+
+  c. BY-NC-SA Compatible License means a license listed at
+     creativecommons.org/compatiblelicenses, approved by Creative
+     Commons as essentially the equivalent of this Public License.
+
+  d. Copyright and Similar Rights means copyright and/or similar rights
+     closely related to copyright including, without limitation,
+     performance, broadcast, sound recording, and Sui Generis Database
+     Rights, without regard to how the rights are labeled or
+     categorized. For purposes of this Public License, the rights
+     specified in Section 2(b)(1)-(2) are not Copyright and Similar
+     Rights.
+
+  e. Effective Technological Measures means those measures that, in the
+     absence of proper authority, may not be circumvented under laws
+     fulfilling obligations under Article 11 of the WIPO Copyright
+     Treaty adopted on December 20, 1996, and/or similar international
+     agreements.
+
+  f. Exceptions and Limitations means fair use, fair dealing, and/or
+     any other exception or limitation to Copyright and Similar Rights
+     that applies to Your use of the Licensed Material.
+
+  g. License Elements means the license attributes listed in the name
+     of a Creative Commons Public License. The License Elements of this
+     Public License are Attribution, NonCommercial, and ShareAlike.
+
+  h. Licensed Material means the artistic or literary work, database,
+     or other material to which the Licensor applied this Public
+     License.
+
+  i. Licensed Rights means the rights granted to You subject to the
+     terms and conditions of this Public License, which are limited to
+     all Copyright and Similar Rights that apply to Your use of the
+     Licensed Material and that the Licensor has authority to license.
+
+  j. Licensor means the individual(s) or entity(ies) granting rights
+     under this Public License.
+
+  k. NonCommercial means not primarily intended for or directed towards
+     commercial advantage or monetary compensation. For purposes of
+     this Public License, the exchange of the Licensed Material for
+     other material subject to Copyright and Similar Rights by digital
+     file-sharing or similar means is NonCommercial provided there is
+     no payment of monetary compensation in connection with the
+     exchange.
+
+  l. Share means to provide material to the public by any means or
+     process that requires permission under the Licensed Rights, such
+     as reproduction, public display, public performance, distribution,
+     dissemination, communication, or importation, and to make material
+     available to the public including in ways that members of the
+     public may access the material from a place and at a time
+     individually chosen by them.
+
+  m. Sui Generis Database Rights means rights other than copyright
+     resulting from Directive 96/9/EC of the European Parliament and of
+     the Council of 11 March 1996 on the legal protection of databases,
+     as amended and/or succeeded, as well as other essentially
+     equivalent rights anywhere in the world.
+
+  n. You means the individual or entity exercising the Licensed Rights
+     under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+  a. License grant.
+
+       1. Subject to the terms and conditions of this Public License,
+          the Licensor hereby grants You a worldwide, royalty-free,
+          non-sublicensable, non-exclusive, irrevocable license to
+          exercise the Licensed Rights in the Licensed Material to:
+
+            a. reproduce and Share the Licensed Material, in whole or
+               in part, for NonCommercial purposes only; and
+
+            b. produce, reproduce, and Share Adapted Material for
+               NonCommercial purposes only.
+
+       2. Exceptions and Limitations. For the avoidance of doubt, where
+          Exceptions and Limitations apply to Your use, this Public
+          License does not apply, and You do not need to comply with
+          its terms and conditions.
+
+       3. Term. The term of this Public License is specified in Section
+          6(a).
+
+       4. Media and formats; technical modifications allowed. The
+          Licensor authorizes You to exercise the Licensed Rights in
+          all media and formats whether now known or hereafter created,
+          and to make technical modifications necessary to do so. The
+          Licensor waives and/or agrees not to assert any right or
+          authority to forbid You from making technical modifications
+          necessary to exercise the Licensed Rights, including
+          technical modifications necessary to circumvent Effective
+          Technological Measures. For purposes of this Public License,
+          simply making modifications authorized by this Section 2(a)
+          (4) never produces Adapted Material.
+
+       5. Downstream recipients.
+
+            a. Offer from the Licensor -- Licensed Material. Every
+               recipient of the Licensed Material automatically
+               receives an offer from the Licensor to exercise the
+               Licensed Rights under the terms and conditions of this
+               Public License.
+
+            b. Additional offer from the Licensor -- Adapted Material.
+               Every recipient of Adapted Material from You
+               automatically receives an offer from the Licensor to
+               exercise the Licensed Rights in the Adapted Material
+               under the conditions of the Adapter's License You apply.
+
+            c. No downstream restrictions. You may not offer or impose
+               any additional or different terms or conditions on, or
+               apply any Effective Technological Measures to, the
+               Licensed Material if doing so restricts exercise of the
+               Licensed Rights by any recipient of the Licensed
+               Material.
+
+       6. No endorsement. Nothing in this Public License constitutes or
+          may be construed as permission to assert or imply that You
+          are, or that Your use of the Licensed Material is, connected
+          with, or sponsored, endorsed, or granted official status by,
+          the Licensor or others designated to receive attribution as
+          provided in Section 3(a)(1)(A)(i).
+
+  b. Other rights.
+
+       1. Moral rights, such as the right of integrity, are not
+          licensed under this Public License, nor are publicity,
+          privacy, and/or other similar personality rights; however, to
+          the extent possible, the Licensor waives and/or agrees not to
+          assert any such rights held by the Licensor to the limited
+          extent necessary to allow You to exercise the Licensed
+          Rights, but not otherwise.
+
+       2. Patent and trademark rights are not licensed under this
+          Public License.
+
+       3. To the extent possible, the Licensor waives any right to
+          collect royalties from You for the exercise of the Licensed
+          Rights, whether directly or through a collecting society
+          under any voluntary or waivable statutory or compulsory
+          licensing scheme. In all other cases the Licensor expressly
+          reserves any right to collect such royalties, including when
+          the Licensed Material is used other than for NonCommercial
+          purposes.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+  a. Attribution.
+
+       1. If You Share the Licensed Material (including in modified
+          form), You must:
+
+            a. retain the following if it is supplied by the Licensor
+               with the Licensed Material:
+
+                 i. identification of the creator(s) of the Licensed
+                    Material and any others designated to receive
+                    attribution, in any reasonable manner requested by
+                    the Licensor (including by pseudonym if
+                    designated);
+
+                ii. a copyright notice;
+
+               iii. a notice that refers to this Public License;
+
+                iv. a notice that refers to the disclaimer of
+                    warranties;
+
+                 v. a URI or hyperlink to the Licensed Material to the
+                    extent reasonably practicable;
+
+            b. indicate if You modified the Licensed Material and
+               retain an indication of any previous modifications; and
+
+            c. indicate the Licensed Material is licensed under this
+               Public License, and include the text of, or the URI or
+               hyperlink to, this Public License.
+
+       2. You may satisfy the conditions in Section 3(a)(1) in any
+          reasonable manner based on the medium, means, and context in
+          which You Share the Licensed Material. For example, it may be
+          reasonable to satisfy the conditions by providing a URI or
+          hyperlink to a resource that includes the required
+          information.
+       3. If requested by the Licensor, You must remove any of the
+          information required by Section 3(a)(1)(A) to the extent
+          reasonably practicable.
+
+  b. ShareAlike.
+
+     In addition to the conditions in Section 3(a), if You Share
+     Adapted Material You produce, the following conditions also apply.
+
+       1. The Adapter's License You apply must be a Creative Commons
+          license with the same License Elements, this version or
+          later, or a BY-NC-SA Compatible License.
+
+       2. You must include the text of, or the URI or hyperlink to, the
+          Adapter's License You apply. You may satisfy this condition
+          in any reasonable manner based on the medium, means, and
+          context in which You Share Adapted Material.
+
+       3. You may not offer or impose any additional or different terms
+          or conditions on, or apply any Effective Technological
+          Measures to, Adapted Material that restrict exercise of the
+          rights granted under the Adapter's License You apply.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+     to extract, reuse, reproduce, and Share all or a substantial
+     portion of the contents of the database for NonCommercial purposes
+     only;
+
+  b. if You include all or a substantial portion of the database
+     contents in a database in which You have Sui Generis Database
+     Rights, then the database in which You have Sui Generis Database
+     Rights (but not its individual contents) is Adapted Material,
+     including for purposes of Section 3(b); and
+
+  c. You must comply with the conditions in Section 3(a) if You Share
+     all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+  c. The disclaimer of warranties and limitation of liability provided
+     above shall be interpreted in a manner that, to the extent
+     possible, most closely approximates an absolute disclaimer and
+     waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+  a. This Public License applies for the term of the Copyright and
+     Similar Rights licensed here. However, if You fail to comply with
+     this Public License, then Your rights under this Public License
+     terminate automatically.
+
+  b. Where Your right to use the Licensed Material has terminated under
+     Section 6(a), it reinstates:
+
+       1. automatically as of the date the violation is cured, provided
+          it is cured within 30 days of Your discovery of the
+          violation; or
+
+       2. upon express reinstatement by the Licensor.
+
+     For the avoidance of doubt, this Section 6(b) does not affect any
+     right the Licensor may have to seek remedies for Your violations
+     of this Public License.
+
+  c. For the avoidance of doubt, the Licensor may also offer the
+     Licensed Material under separate terms or conditions or stop
+     distributing the Licensed Material at any time; however, doing so
+     will not terminate this Public License.
+
+  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+     License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+  a. The Licensor shall not be bound by any additional or different
+     terms or conditions communicated by You unless expressly agreed.
+
+  b. Any arrangements, understandings, or agreements regarding the
+     Licensed Material not stated herein are separate from and
+     independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+  a. For the avoidance of doubt, this Public License does not, and
+     shall not be interpreted to, reduce, limit, restrict, or impose
+     conditions on any use of the Licensed Material that could lawfully
+     be made without permission under this Public License.
+
+  b. To the extent possible, if any provision of this Public License is
+     deemed unenforceable, it shall be automatically reformed to the
+     minimum extent necessary to make it enforceable. If the provision
+     cannot be reformed, it shall be severed from this Public License
+     without affecting the enforceability of the remaining terms and
+     conditions.
+
+  c. No term or condition of this Public License will be waived and no
+     failure to comply consented to unless expressly agreed to by the
+     Licensor.
+
+  d. Nothing in this Public License constitutes or may be interpreted
+     as a limitation upon, or waiver of, any privileges and immunities
+     that apply to the Licensor or You, including from the legal
+     processes of any jurisdiction or authority.
+
+=======================================================================
+
+Creative Commons is not a party to its public licenses.
+Notwithstanding, Creative Commons may elect to apply one of its public
+licenses to material it publishes and in those instances will be
+considered the "Licensor." Except for the limited purpose of indicating
+that material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the public
+licenses.
+
+Creative Commons may be contacted at creativecommons.org.
+
diff --git a/ui/text/README.md b/ui/text/README.md
new file mode 100644
index 0000000..e611954
--- /dev/null
+++ b/ui/text/README.md
@@ -0,0 +1,75 @@
+Text Styling
+============
+These samples shows how to style text on Android using spans, in [Java](https://github.com/googlesamples/android-text/tree/master/TextStyling-Java) and in [Kotlin](https://github.com/googlesamples/android-text/tree/master/TextStyling-Kotlin).
+
+
+Introduction
+------------
+The difference between [TextStyling-Java](https://github.com/googlesamples/android-text/tree/master/TextStyling-Java) and [TextStyling-Kotlin](https://github.com/googlesamples/android-text/tree/master/TextStyling-Kotlin) is only in the language. They have the same set of features, same class names and similar ways of testing the functionality.
+## Features
+Parse some hardcoded text and do the following:
+* Paragraphs starting with “> ” are transformed into quotes.
+* Text enclosed in “```” will be transformed into inline code block.
+* Lines starting with “+ ” or “* ” will be transformed into bullet points.
+To update the text, modify the value of `R.string.display_text`.
+This project is not meant to fully cover the markdown capabilities and has several limitations; for example, quotes do not support nesting other elements.
+
+## Implementation
+The text is parsed in the `Parser.parse` method and the spans are created in the `MarkdownBuilder.markdownToSpans` method.
+To see how to apply a span, check out `MarkdownBuilder.buildCodeBlockSpan`. To see how to apply multiple spans on the same string, see `MarkdownBuilder.buildQuoteSpan`. For examples of creating custom spans, see `BulletPointSpan`, `CodeBlockSpan` or `FontSpan`.
+
+## Testing
+Text parsing is tested with JUnit tests in `ParserTest`. Span building is tested via Android JUnit tests, in `MarkdownBuilderTest`.
+
+
+Getting Started
+---------------
+
+Clone this repository, enter the top level directory and run `./gradlew tasks`
+to get an overview of all the tasks available for this project.
+
+Some important tasks are:
+
+```
+assembleDebug - Assembles all Debug builds.
+installDebug - Installs the Debug build.
+connectedAndroidTest - Installs and runs the tests for Debug build on connected
+devices.
+test - Run all unit tests.
+```
+
+Screenshots
+-----------
+<img src="screenshots/main_activity.png" width="30%" />
+
+Support
+-------
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android-text
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-text/issues
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub.
+
+License
+--------
+```
+Copyright 2018 The Android Open Source Project
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+```
+
diff --git a/ui/text/TextStyling-Java/.gitignore b/ui/text/TextStyling-Java/.gitignore
new file mode 100644
index 0000000..0b39def
--- /dev/null
+++ b/ui/text/TextStyling-Java/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+/projectFilesBackup
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/README.md b/ui/text/TextStyling-Java/README.md
new file mode 100644
index 0000000..e76fc35
--- /dev/null
+++ b/ui/text/TextStyling-Java/README.md
@@ -0,0 +1,73 @@
+Text Styling
+============
+This sample shows how to style text on Android using spans, in Java.
+
+Introduction
+------------
+## Features
+Parse some hardcoded text and do the following:
+* Paragraphs starting with “> ” are transformed into quotes.
+* Text enclosed in “```” will be transformed into inline code block.
+* Lines starting with “+ ” or “* ” will be transformed into bullet points.
+To update the text, modify the value of `R.string.display_text`.
+This project is not meant to fully cover the markdown capabilities and has several limitations; for example, quotes do not support nesting other elements.
+
+## Implementation
+The text is parsed in the [`Parser.parse`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/Parser.java#L62) method and the spans are created in the [`MarkdownBuilder.markdownToSpans`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.java#L62) method.
+To see how to apply a span, check out [`MarkdownBuilder.buildCodeBlockSpan`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.java#L120) . To see how to apply multiple spans on the same string, see [`MarkdownBuilder.buildQuoteSpan`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.java#L108). For examples of creating custom spans, see [`BulletPointSpan`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/BulletPointSpan.java), [`CodeBlockSpan`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/CodeBlockSpan.java) or [`FontSpan`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/FontSpan.java).
+
+## Testing
+Text parsing is tested with JUnit tests in [`ParserTest`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Java/app/src/test/java/com/android/example/text/styling/parser/ParserTest.java). Span building is tested via Android JUnit tests, in [`MarkdownBuilderTest`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/MarkdownBuilderTest.java).
+
+
+Getting Started
+---------------
+
+Clone this repository, enter the top level directory and run `./gradlew tasks`
+to get an overview of all the tasks available for this project.
+
+Some important tasks are:
+
+```
+assembleDebug - Assembles all Debug builds.
+installDebug - Installs the Debug build.
+connectedAndroidTest - Installs and runs the tests for Debug build on connected
+devices.
+test - Run all unit tests.
+```
+
+Screenshots
+-----------
+<img src="../screenshots/main_activity.png" width="30%" />
+
+Support
+-------
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android-text
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-text/issues
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub.
+
+License
+--------
+```
+Copyright 2018 The Android Open Source Project
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+```
+
diff --git a/ui/text/TextStyling-Java/app/.gitignore b/ui/text/TextStyling-Java/app/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/.gitignore
diff --git a/ui/text/TextStyling-Java/app/build.gradle b/ui/text/TextStyling-Java/app/build.gradle
new file mode 100644
index 0000000..5a38ade
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/build.gradle
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion rootProject.ext.compileSdkVersion
+    buildToolsVersion rootProject.ext.buildToolsVersion
+
+    defaultConfig {
+        applicationId "com.android.example.text.styling"
+        minSdkVersion rootProject.ext.minSdkVersion
+        targetSdkVersion rootProject.ext.targetSdkVersion
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+    buildTypes {
+        release {
+            postprocessing {
+                removeUnusedCode false
+                removeUnusedResources false
+                obfuscate false
+                optimizeCode false
+                proguardFile 'proguard-rules.pro'
+            }
+        }
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
+    implementation "com.android.support.constraint:constraint-layout:$constraintLayoutVersion"
+
+    // Dependencies for local unit tests
+    testImplementation "junit:junit:$junitVersion"
+
+    androidTestImplementation "org.mockito:mockito-core:$mockitoVersion"
+    androidTestImplementation "com.android.support.test:runner:$runnerVersion"
+    androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
+    androidTestImplementation "com.google.dexmaker:dexmaker:$dexmakerVersion"
+    androidTestImplementation "com.google.dexmaker:dexmaker-mockito:$dexmakerMockitoVersion"
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/proguard-rules.pro b/ui/text/TextStyling-Java/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/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/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/MarkdownBuilderTest.java b/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/MarkdownBuilderTest.java
new file mode 100644
index 0000000..30b8a61
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/MarkdownBuilderTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.example.text.styling.renderer;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.support.test.InstrumentationRegistry;
+import android.support.v4.content.res.ResourcesCompat;
+import android.text.SpannedString;
+import android.text.style.LeadingMarginSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StyleSpan;
+
+import com.android.example.text.styling.R;
+import com.android.example.text.styling.parser.Parser;
+import com.android.example.text.styling.renderer.spans.BulletPointSpan;
+import com.android.example.text.styling.renderer.spans.CodeBlockSpan;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class MarkdownBuilderTest {
+
+    private MarkdownBuilder builder;
+
+    public MarkdownBuilderTest() {
+        Context context = InstrumentationRegistry.getTargetContext();
+        int bulletPointColor = context.getColor(R.color.colorAccent);
+        int codeBackgroundColor = context.getColor(R.color.code_background);
+        Typeface codeBlockTypeface = ResourcesCompat.getFont(context, R.font.inconsolata);
+        builder = new MarkdownBuilder(bulletPointColor, codeBackgroundColor, codeBlockTypeface,
+                new Parser());
+    }
+
+    @Test
+    public void builder() {
+        SpannedString result = builder.markdownToSpans("Hello, world!");
+        assertEquals("Hello, world!", result.toString());
+    }
+
+    @Test
+    public void text() {
+        SpannedString result = builder.markdownToSpans("Text");
+
+        Object[] spans = result.getSpans(0, result.length(), Object.class);
+        assertEquals(0, spans.length);
+    }
+
+    @Test
+    public void textWithQuote() {
+        SpannedString result = builder.markdownToSpans("Text\n> Quote");
+
+        assertEquals("Text\nQuote", result.toString());
+        Object[] spans = result.getSpans(0, result.length(), Object.class);
+        assertEquals(3, spans.length);
+
+        StyleSpan styleSpan = (StyleSpan) spans[0];
+        assertEquals(Typeface.ITALIC, styleSpan.getStyle());
+        assertEquals(5, result.getSpanStart(styleSpan));
+        assertEquals(10, result.getSpanEnd(styleSpan));
+        LeadingMarginSpan leadingMarginSpan = (LeadingMarginSpan) spans[1];
+        assertEquals(5, result.getSpanStart(leadingMarginSpan));
+        assertEquals(10, result.getSpanEnd(leadingMarginSpan));
+        RelativeSizeSpan relativeSizeSpan = (RelativeSizeSpan) spans[2];
+        assertEquals(5, result.getSpanStart(relativeSizeSpan));
+        assertEquals(10, result.getSpanEnd(relativeSizeSpan));
+    }
+
+    @Test
+    public void textWithBulletPoints() {
+        SpannedString result = builder.markdownToSpans("Points\n* one\n+ two");
+
+        assertEquals("Points\none\ntwo", result.toString());
+        Object[] spans = result.getSpans(0, result.length(), Object.class);
+        assertEquals(2, spans.length);
+
+        BulletPointSpan bulletSpan = (BulletPointSpan) spans[0];
+        assertEquals(7, result.getSpanStart(bulletSpan));
+        assertEquals(11, result.getSpanEnd(bulletSpan));
+        BulletPointSpan bulletSpan2 = (BulletPointSpan) spans[1];
+        assertEquals(11, result.getSpanStart(bulletSpan2));
+        assertEquals(14, result.getSpanEnd(bulletSpan2));
+    }
+
+    @Test
+    public void textWithCode() {
+        SpannedString result = builder.markdownToSpans("Text `code`");
+
+        assertEquals("Text code", result.toString());
+        Object[] spans = result.getSpans(0, result.length(), Object.class);
+        assertEquals(1, spans.length);
+
+        CodeBlockSpan codeSpan = (CodeBlockSpan) spans[0];
+        assertEquals(5, result.getSpanStart(codeSpan));
+        assertEquals(9, result.getSpanEnd(codeSpan));
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/BulletPointSpanTest.java b/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/BulletPointSpanTest.java
new file mode 100644
index 0000000..305e543
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/BulletPointSpanTest.java
@@ -0,0 +1,114 @@
+package com.android.example.text.styling.renderer.spans;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.text.Layout;
+import android.text.SpannableString;
+import android.text.Spanned;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Matchers;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link BulletPointSpan} class
+ */
+public class BulletPointSpanTest {
+
+    private static final int GAP_WIDTH = 5;
+    private Canvas canvas = mock(Canvas.class);
+    private Paint paint = mock(Paint.class);
+    private SpannableString text = new SpannableString("text");
+
+    @Test
+    public void getLeadingMargin() {
+        // Given a span with a certain gap width
+        BulletPointSpan span = new BulletPointSpan(GAP_WIDTH, 0);
+
+        // Check that the margin is set correctly
+        int expectedMargin = (int) (2 * BulletPointSpan.BULLET_RADIUS + 2 * GAP_WIDTH);
+        assertEquals(expectedMargin, span.getLeadingMargin(true));
+    }
+
+    @Test
+    public void drawLeadingMarginWithoutText() {
+        // Given a span
+        BulletPointSpan span = new BulletPointSpan(GAP_WIDTH, 0);
+
+        // When the leading margin is drawn but no text is set
+        span.drawLeadingMargin(canvas, paint, 0, 0, 0, 0, 0, text, 0, 0, true,
+                mock(Layout.class));
+
+        // Check that no drawing methods are called
+        verifyZeroInteractions(canvas);
+        verifyZeroInteractions(paint);
+    }
+
+    @Test
+    public void drawLeadingMarginHardwareAccelerated() {
+        int x = 10;
+        int dir = 15;
+        int top = 5;
+        int bottom = 7;
+        int color = Color.RED;
+        // Given a span that is set on a text
+        BulletPointSpan span = new BulletPointSpan(GAP_WIDTH, color);
+        text.setSpan(span, 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        when(canvas.isHardwareAccelerated()).thenReturn(true);
+
+        // When the leading margin is drawn
+        span.drawLeadingMargin(canvas, paint, x, dir, top, 0, bottom, text, 0, 0, true, mock
+                (Layout.class));
+
+        // Check that the correct canvas and paint methods are called, in the correct order
+        InOrder inOrder = inOrder(canvas, paint);
+        inOrder.verify(paint).setColor(color);
+        inOrder.verify(paint).setStyle(eq(Paint.Style.FILL));
+        inOrder.verify(canvas).save();
+        inOrder.verify(canvas).translate(
+                eq(GAP_WIDTH + x + dir * BulletPointSpan.BULLET_RADIUS),
+                eq((top + bottom) / 2f));
+        inOrder.verify(canvas).drawPath(Matchers.any(Path.class), eq(paint));
+        inOrder.verify(canvas).restore();
+    }
+
+    @Test
+    public void drawLeadingMarginNotHardwareAccelerated() {
+        int x = 10;
+        int dir = 15;
+        int top = 5;
+        int bottom = 7;
+        int color = Color.RED;
+        // Given a span that is set on a text
+        BulletPointSpan span = new BulletPointSpan(GAP_WIDTH, color);
+        text.setSpan(span, 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        when(canvas.isHardwareAccelerated()).thenReturn(false);
+
+        // When the leading margin is drawn
+        span.drawLeadingMargin(canvas, paint, x, dir, top, 0, bottom, text, 0, 0, true, mock
+                (Layout.class));
+
+        // Check that the correct canvas and paint methods are called, in the correct order
+        InOrder inOrder = inOrder(canvas, paint);
+        inOrder.verify(paint).setColor(color);
+        inOrder.verify(paint).setStyle(eq(Paint.Style.FILL));
+        inOrder.verify(canvas).drawCircle(eq(GAP_WIDTH + x + dir * BulletPointSpan.BULLET_RADIUS),
+                eq((top + bottom) / 2f), eq(BulletPointSpan.BULLET_RADIUS), eq(paint));
+        verify(canvas, never()).save();
+        verify(canvas, never()).translate(
+                eq(GAP_WIDTH + x + dir * BulletPointSpan.BULLET_RADIUS),
+                eq((top + bottom) / 2f));
+        verify(canvas, never()).restore();
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/CodeBlockSpanTest.java b/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/CodeBlockSpanTest.java
new file mode 100644
index 0000000..81efd11
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/CodeBlockSpanTest.java
@@ -0,0 +1,28 @@
+package com.android.example.text.styling.renderer.spans;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.text.TextPaint;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link CodeBlockSpan} class
+ */
+public class CodeBlockSpanTest {
+
+    private TextPaint paint = mock(TextPaint.class);
+    private CodeBlockSpan span = new CodeBlockSpan(Typeface.DEFAULT, Color.RED);
+
+    @Test
+    public void updateDrawState() {
+        // When the update draw state is called
+        span.updateDrawState(paint);
+
+        // Check that the correct color is set
+        assertEquals(Color.RED, paint.bgColor);
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/FontSpanTest.java b/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/FontSpanTest.java
new file mode 100644
index 0000000..d812695
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/FontSpanTest.java
@@ -0,0 +1,52 @@
+package com.android.example.text.styling.renderer.spans;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Typeface;
+import android.text.TextPaint;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+/**
+ * Tests for the {@link FontSpan} class
+ */
+public class FontSpanTest {
+
+    private TextPaint paint = mock(TextPaint.class);
+    private FontSpan span = new FontSpan(Typeface.DEFAULT);
+    private Typeface defaultTypeface = Typeface.create("serif", Typeface.BOLD);
+
+    @Before
+    public void setUp() {
+        when(paint.getTypeface()).thenReturn(defaultTypeface);
+    }
+
+    @Test
+    public void updateMeasureState() {
+        // When the update measure state is called
+        span.updateMeasureState(paint);
+
+        // Check that the typeface set has the correct typeface and style
+        ArgumentCaptor<Typeface> captor = ArgumentCaptor.forClass(Typeface.class);
+        verify(paint).setTypeface(captor.capture());
+        assertEquals(Typeface.BOLD, captor.getValue().getStyle());
+    }
+
+    @Test
+    public void updateDrawState() {
+        // When the update draw state is called
+        span.updateDrawState(paint);
+
+        // Check that the typeface set has the correct typeface and style
+        ArgumentCaptor<Typeface> captor = ArgumentCaptor.forClass(Typeface.class);
+        verify(paint).setTypeface(captor.capture());
+        assertEquals(Typeface.BOLD, captor.getValue().getStyle());
+    }
+
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/src/main/AndroidManifest.xml b/ui/text/TextStyling-Java/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..675a7bd
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.example.text.styling">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts"/>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/MainActivity.java b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/MainActivity.java
new file mode 100644
index 0000000..1b45282
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/MainActivity.java
@@ -0,0 +1,55 @@
+/*
+ * 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.example.text.styling;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.TextView;
+
+import com.android.example.text.styling.parser.Parser;
+import com.android.example.text.styling.renderer.MarkdownBuilder;
+
+/**
+ * This sample demonstrates techniques for stying text; it is not intended to be a full markdown
+ * parser.
+ */
+public class MainActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        TextView textView = findViewById(R.id.styled_text);
+
+        // This is a simple markdown parser, where:
+        // Paragraphs starting with “> ” are transformed into quotes. Quotes can't contain
+        // other markdown elements
+        // Text enclosed in “`” will be transformed into inline code block
+        // Lines starting with “+ ” or “* ” will be transformed into bullet points. Bullet
+        // points can contain nested markdown elements, like code.
+        int bulletPointColor = ContextCompat.getColor(this, R.color.colorAccent);
+        int codeBackgroundColor = ContextCompat.getColor(this, R.color.code_background);
+        Typeface codeBlockTypeface = ResourcesCompat.getFont(this, R.font.inconsolata);
+
+        CharSequence text = new MarkdownBuilder(bulletPointColor, codeBackgroundColor,
+                codeBlockTypeface, new Parser())
+                .markdownToSpans(getString(R.string.display_text));
+        textView.setText(text);
+    }
+}
diff --git a/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/Element.java b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/Element.java
new file mode 100644
index 0000000..172ac87
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/Element.java
@@ -0,0 +1,64 @@
+/*
+ * 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.example.text.styling.parser;
+
+import android.support.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * Markdown like type of element.
+ */
+public class Element {
+
+    public enum Type {TEXT, QUOTE, BULLET_POINT, CODE_BLOCK}
+
+    @NonNull
+    private final Type type;
+
+    @NonNull
+    private final String text;
+
+    @NonNull
+    private final List<Element> elements;
+
+    public Element(@NonNull final Type type, @NonNull final String text,
+            @NonNull final List<Element> elements) {
+        this.type = type;
+        this.text = text;
+        this.elements = elements;
+    }
+
+    @NonNull
+    public Type getType() {
+        return type;
+    }
+
+    @NonNull
+    public String getText() {
+        return text;
+    }
+
+    @NonNull
+    public List<Element> getElements() {
+        return elements;
+    }
+
+    @Override
+    public String toString() {
+        return type + " " + text;
+    }
+}
diff --git a/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/Parser.java b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/Parser.java
new file mode 100644
index 0000000..a79096d
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/Parser.java
@@ -0,0 +1,166 @@
+/*
+ * 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.example.text.styling.parser;
+
+import android.support.annotation.NonNull;
+
+import com.android.example.text.styling.parser.Element.Type;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * The role of this parser is just to showcase ways of working with text. It should not be
+ * expected to support complex markdown elements.
+ *
+ * Parse a text and extract markdown elements:
+ * <ul>
+ * <li>Paragraphs starting with “> ” are transformed into quotes. Quotes can't contain
+ * other markdown elements</li>
+ * <li> Text enclosed in “```” will be transformed into inline code block</li>
+ * <li>Lines starting with “+ ” or “* ” will be transformed into bullet points. Bullet
+ * points can contain nested markdown elements, like code.</li>
+ * </ul>
+ */
+public class Parser {
+    private static final String BULLET_PLUS = "+ ";
+    private static final String BULLET_STAR = "* ";
+    private static final String QUOTE_REGEX = "(?m)^> ";
+    private static final String BULLET_POINT_STAR = "(?m)^\\* ";
+    private static final String BULLET_POINT_PLUS = "(?m)^\\+ ";
+    private static final String BULLET_POINT_REGEX = "(" + BULLET_POINT_STAR + "|" +
+            BULLET_POINT_PLUS + ")";
+    private static final String CODE_BLOCK = "`";
+    private static final String BULLET_POINT_CODE_BLOCK_REGEX = "(" + BULLET_POINT_REGEX + "|" +
+            CODE_BLOCK + ")";
+
+    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+    /**
+     * Parse a text and extract the {@link TextMarkdown}.
+     *
+     * @param string string to be parsed into markdown elements
+     * @return the {@link TextMarkdown}
+     */
+    @NonNull
+    public TextMarkdown parse(@NonNull final String string) {
+        List<Element> parents = new ArrayList<>();
+
+        Pattern quotePattern = Pattern.compile(QUOTE_REGEX);
+        Pattern pattern = Pattern.compile(BULLET_POINT_CODE_BLOCK_REGEX);
+
+        Matcher matcher = quotePattern.matcher(string);
+        int lastStartIndex = 0;
+
+        while (matcher.find(lastStartIndex)) {
+            int startIndex = matcher.start();
+            int endIndex = matcher.end();
+            // we found a quote
+            if (lastStartIndex < startIndex) {
+                // check what was before the quote
+                String text = string.substring(lastStartIndex, startIndex);
+                parents.addAll(findElements(text, pattern));
+            }
+            // a quote can only be a paragraph long, so look for end of line
+            int endOfQuote = getEndOfParagraph(string, endIndex);
+            lastStartIndex = endOfQuote;
+            String quotedText = string.substring(endIndex, endOfQuote);
+            parents.add(new Element(Type.QUOTE, quotedText, Collections.<Element>emptyList()));
+        }
+        // check if there are any other element after the quote
+        if (lastStartIndex < string.length()) {
+            String text = string.substring(lastStartIndex, string.length());
+            parents.addAll(findElements(text, pattern));
+        }
+
+        return new TextMarkdown(parents);
+    }
+
+    private static int getEndOfParagraph(@NonNull String string, int endIndex) {
+        int endOfParagraph = string.indexOf(LINE_SEPARATOR, endIndex);
+        if (endOfParagraph == -1) {
+            // we don't have an end of line, so the quote is the last element in the text
+            // so we can consider that the end of the quote is the end of the text
+            endOfParagraph = string.length();
+        } else {
+            // add the new line as part of the element
+            endOfParagraph++;
+        }
+        return endOfParagraph;
+    }
+
+    @NonNull
+    private static List<Element> findElements(@NonNull final String string,
+            @NonNull final Pattern pattern) {
+        List<Element> parents = new ArrayList<>();
+        Matcher matcher = pattern.matcher(string);
+        int lastStartIndex = 0;
+
+        while (matcher.find(lastStartIndex)) {
+            int startIndex = matcher.start();
+            int endIndex = matcher.end();
+            // we found a mark
+            String mark = string.substring(startIndex, endIndex);
+            if (lastStartIndex < startIndex) {
+                // check what was before the mark
+                parents.addAll(findElements(string.substring(lastStartIndex, startIndex), pattern));
+            }
+            String text;
+            // check what kind of mark this was
+            switch (mark) {
+                case BULLET_PLUS:
+                case BULLET_STAR:
+                    // every bullet point is max until a new line or end of text
+                    int endOfBulletPoint = getEndOfParagraph(string, endIndex);
+                    text = string.substring(endIndex, endOfBulletPoint);
+                    lastStartIndex = endOfBulletPoint;
+                    // also see what else we have in the text
+                    List<Element> subMarks = findElements(text, pattern);
+                    Element bulletPoint = new Element(Type.BULLET_POINT, text, subMarks);
+                    parents.add(bulletPoint);
+                    break;
+                case CODE_BLOCK:
+                    // a code block is set between two "`" so look for the other one
+                    // if another "`" is not found, then this is not a code block
+                    int markEnd = string.indexOf(CODE_BLOCK, endIndex);
+                    if (markEnd == -1) {
+                        // we don't have an end of code block so this is just text
+                        markEnd = string.length();
+                        text = string.substring(startIndex, markEnd);
+                        parents.add(new Element(Type.TEXT, text, Collections.<Element>emptyList()));
+                        lastStartIndex = markEnd;
+                    } else {
+                        // we found the end of the code block
+                        text = string.substring(endIndex, markEnd);
+                        parents.add(new Element(Type.CODE_BLOCK, text,
+                                Collections.<Element>emptyList()));
+                        // adding 1 so we can ignore the ending "`" for the code block
+                        lastStartIndex = markEnd + 1;
+                    }
+                    break;
+            }
+        }
+        // check if there's any more text left
+        if (lastStartIndex < string.length()) {
+            String text = string.substring(lastStartIndex, string.length());
+            parents.add(new Element(Type.TEXT, text, Collections.<Element>emptyList()));
+        }
+        return parents;
+    }
+}
diff --git a/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/TextMarkdown.java b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/TextMarkdown.java
new file mode 100644
index 0000000..24279b9
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/parser/TextMarkdown.java
@@ -0,0 +1,39 @@
+/*
+ * 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.example.text.styling.parser;
+
+import android.support.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * Simple markdown parsing of text.
+ * Contains a list of markdown {@link Element}s
+ */
+public class TextMarkdown {
+
+    @NonNull
+    private final List<Element> elements;
+
+    public TextMarkdown(@NonNull final List<Element> elements) {
+        this.elements = elements;
+    }
+
+    @NonNull
+    public List<Element> getElements() {
+        return elements;
+    }
+}
diff --git a/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.java b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.java
new file mode 100644
index 0000000..e084b70
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.java
@@ -0,0 +1,126 @@
+/*
+ * 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.example.text.styling.renderer;
+
+import android.graphics.Typeface;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.SpannedString;
+import android.text.style.LeadingMarginSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StyleSpan;
+
+import com.android.example.text.styling.parser.Element;
+import com.android.example.text.styling.parser.Parser;
+import com.android.example.text.styling.parser.TextMarkdown;
+import com.android.example.text.styling.renderer.spans.BulletPointSpan;
+import com.android.example.text.styling.renderer.spans.CodeBlockSpan;
+
+/**
+ * Renders the text as simple markdown, using spans.
+ */
+public class MarkdownBuilder {
+
+    @ColorInt
+    private final int bulletPointColor;
+
+    @ColorInt
+    private final int codeBackgroundColor;
+
+    @Nullable
+    private final Typeface codeBlockTypeface;
+
+    @NonNull
+    private final Parser parser;
+
+    public MarkdownBuilder(@ColorInt final int bulletPointColor,
+                           @ColorInt final int codeBackgroundColor,
+                           final Typeface codeBlockTypeface,
+                           @NonNull final Parser parser) {
+        this.bulletPointColor = bulletPointColor;
+        this.codeBackgroundColor = codeBackgroundColor;
+        this.codeBlockTypeface = codeBlockTypeface;
+        this.parser = parser;
+    }
+
+    public SpannedString markdownToSpans(@NonNull final String string) {
+        TextMarkdown markdown = parser.parse(string);
+
+        // In the SpannableStringBuilder, the text and the markup are mutable.
+        SpannableStringBuilder builder = new SpannableStringBuilder();
+        for (int i = 0; i < markdown.getElements().size(); i++) {
+            buildSpans(markdown.getElements().get(i), builder);
+        }
+        return new SpannedString(builder);
+    }
+
+    /**
+     * Build the spans for an element and insert them in the builder
+     *
+     * @param element the element for which the spans are built
+     * @param builder a {@link SpannableStringBuilder} that gathers all the spans
+     */
+    private void buildSpans(@NonNull final Element element,
+                            @NonNull final SpannableStringBuilder builder) {
+        // apply different spans depending on the type of the element
+        switch (element.getType()) {
+            case CODE_BLOCK:
+                buildCodeBlockSpan(element, builder);
+                break;
+            case QUOTE:
+                buildQuoteSpans(element, builder);
+                break;
+            case BULLET_POINT:
+                buildBulletPointSpans(element, builder);
+                break;
+            case TEXT:
+                builder.append(element.getText());
+                break;
+        }
+    }
+
+    private void buildBulletPointSpans(@NonNull final Element element,
+                                       @NonNull final SpannableStringBuilder builder) {
+        int startIndex = builder.length();
+        for (Element child : element.getElements()) {
+            buildSpans(child, builder);
+        }
+        builder.setSpan(new BulletPointSpan(20, bulletPointColor), startIndex,
+                builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+    }
+
+    private void buildQuoteSpans(@NonNull Element element, SpannableStringBuilder builder) {
+        int startIndex = builder.length();
+        builder.append(element.getText());
+        // You can set multiple spans for the same text
+        builder.setSpan(new StyleSpan(Typeface.ITALIC), startIndex, builder.length(),
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        builder.setSpan(new LeadingMarginSpan.Standard(40), startIndex, builder.length(),
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        builder.setSpan(new RelativeSizeSpan(1.1f), startIndex, builder.length(),
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+    }
+
+    private void buildCodeBlockSpan(@NonNull Element element, SpannableStringBuilder builder) {
+        int startIndex = builder.length();
+        builder.append(element.getText());
+        builder.setSpan(new CodeBlockSpan(codeBlockTypeface, codeBackgroundColor), startIndex,
+                builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+    }
+}
diff --git a/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/BulletPointSpan.java b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/BulletPointSpan.java
new file mode 100644
index 0000000..8467eb9
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/BulletPointSpan.java
@@ -0,0 +1,85 @@
+/*
+ * 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.example.text.styling.renderer.spans;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.support.annotation.ColorInt;
+import android.support.annotation.Px;
+import android.support.annotation.VisibleForTesting;
+import android.text.Layout;
+import android.text.Spanned;
+import android.text.style.BulletSpan;
+import android.text.style.LeadingMarginSpan;
+
+/**
+ * Creating a bullet span with bigger bullets than {@link BulletSpan} and with a left margin
+ */
+public class BulletPointSpan implements LeadingMarginSpan {
+
+    @VisibleForTesting
+    static final float BULLET_RADIUS = 15.0f;
+
+    private final @Px int gapWidth;
+    private final @ColorInt int color;
+
+    private static Path bulletPath;
+
+    public BulletPointSpan(@Px int gapWidth, @ColorInt int color) {
+        this.gapWidth = gapWidth;
+        this.color = color;
+    }
+
+    @Override
+    public int getLeadingMargin(boolean first) {
+        return (int) (2 * BULLET_RADIUS + 2 * gapWidth);
+    }
+
+    @Override
+    public void drawLeadingMargin(Canvas canvas, Paint paint, int x, int dir,
+            int top, int baseline, int bottom,
+            CharSequence text, int start, int end,
+            boolean first, Layout l) {
+        if (((Spanned) text).getSpanStart(this) == start) {
+            Paint.Style style = paint.getStyle();
+            int oldcolor = paint.getColor();
+            paint.setColor(color);
+
+            paint.setStyle(Paint.Style.FILL);
+
+            final float y = (top + bottom) / 2f;
+
+            if (canvas.isHardwareAccelerated()) {
+                if (bulletPath == null) {
+                    bulletPath = new Path();
+                    bulletPath.addCircle(0.0f, 0.0f, BULLET_RADIUS, Path.Direction.CW);
+                }
+
+                canvas.save();
+                canvas.translate(gapWidth + x + dir * BULLET_RADIUS, y);
+                canvas.drawPath(bulletPath, paint);
+                canvas.restore();
+            } else {
+                canvas.drawCircle(gapWidth + x + dir * BULLET_RADIUS, y, BULLET_RADIUS, paint);
+            }
+
+            // restore
+            paint.setColor(oldcolor);
+            paint.setStyle(style);
+        }
+    }
+}
diff --git a/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/CodeBlockSpan.java b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/CodeBlockSpan.java
new file mode 100644
index 0000000..3a49680
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/CodeBlockSpan.java
@@ -0,0 +1,45 @@
+/*
+ * 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.example.text.styling.renderer.spans;
+
+import android.graphics.Typeface;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.text.TextPaint;
+import android.text.style.BackgroundColorSpan;
+
+/**
+ * To draw a code block, we set a font for the text and a background color.
+ * The same effect can be achieved if on a text block, we set two spans: {@link FontSpan} and
+ * {@link BackgroundColorSpan}
+ */
+public class CodeBlockSpan extends FontSpan {
+
+    private final @ColorInt int backgroundColor;
+
+    public CodeBlockSpan(@NonNull final Typeface font, final @ColorInt int backgroundColor) {
+        super(font);
+        this.backgroundColor = backgroundColor;
+    }
+
+    // Since we're only changing the background color, it will not affect the measure state, so
+    // just override the update draw state.
+    @Override
+    public void updateDrawState(TextPaint textPaint) {
+        super.updateDrawState(textPaint);
+        textPaint.bgColor = backgroundColor;
+    }
+}
diff --git a/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/FontSpan.java b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/FontSpan.java
new file mode 100644
index 0000000..c378231
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/java/com/android/example/text/styling/renderer/spans/FontSpan.java
@@ -0,0 +1,57 @@
+/*
+ * 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.example.text.styling.renderer.spans;
+
+import android.annotation.SuppressLint;
+import android.graphics.Typeface;
+import android.support.annotation.Nullable;
+import android.text.TextPaint;
+import android.text.style.MetricAffectingSpan;
+
+/**
+ * Span that changes the typeface of the text used to the one provided. The style set before will
+ * be kept.
+ */
+public class FontSpan extends MetricAffectingSpan {
+
+    @Nullable
+    private final Typeface font;
+
+    public FontSpan(@Nullable final Typeface font) {
+        this.font = font;
+    }
+
+    @Override
+    public void updateMeasureState(TextPaint textPaint) {
+        update(textPaint);
+    }
+
+    @Override
+    public void updateDrawState(TextPaint textPaint) {
+        update(textPaint);
+    }
+
+    @SuppressLint("WrongConstant")
+    private void update(TextPaint textPaint) {
+        Typeface old = textPaint.getTypeface();
+        int oldStyle = old != null ? old.getStyle() : 0;
+
+        // Typeface is already cached at the system level
+        // keep the style set before
+        Typeface font = Typeface.create(this.font, oldStyle);
+        textPaint.setTypeface(font);
+    }
+}
diff --git a/ui/text/TextStyling-Java/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/ui/text/TextStyling-Java/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..c3903ed
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:aapt="http://schemas.android.com/aapt"
+        android:width="108dp"
+        android:height="108dp"
+        android:viewportHeight="108"
+        android:viewportWidth="108">
+    <path
+        android:fillType="evenOdd"
+        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+        android:strokeColor="#00000000"
+        android:strokeWidth="1">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="78.5885"
+                android:endY="90.9159"
+                android:startX="48.7653"
+                android:startY="61.0927"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0"/>
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0"/>
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+        android:strokeColor="#00000000"
+        android:strokeWidth="1"/>
+</vector>
diff --git a/ui/text/TextStyling-Java/app/src/main/res/drawable/ic_launcher_background.xml b/ui/text/TextStyling-Java/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..9d478f4
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportHeight="108"
+    android:viewportWidth="108">
+    <path android:fillColor="#26A69A"
+          android:pathData="M0,0h108v108h-108z"/>
+    <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,0L29,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,0L39,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,0L49,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,0L59,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,0L69,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,0L79,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M89,0L89,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M99,0L99,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,9L108,9"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,19L108,19"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,29L108,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,39L108,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,49L108,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,59L108,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,69L108,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,79L108,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,89L108,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,99L108,99"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,29L89,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,39L89,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,49L89,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,59L89,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,69L89,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,79L89,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,19L29,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,19L39,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,19L49,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,19L59,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+</vector>
diff --git a/ui/text/TextStyling-Java/app/src/main/res/font/inconsolata.xml b/ui/text/TextStyling-Java/app/src/main/res/font/inconsolata.xml
new file mode 100644
index 0000000..5577633
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/font/inconsolata.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
+        app:fontProviderAuthority="com.google.android.gms.fonts"
+        app:fontProviderPackage="com.google.android.gms"
+        app:fontProviderQuery="Inconsolata"
+        app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
+</font-family>
diff --git a/ui/text/TextStyling-Java/app/src/main/res/layout/activity_main.xml b/ui/text/TextStyling-Java/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..f43874f
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,35 @@
+<?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.
+  -->
+<android.support.constraint.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=".MainActivity">
+
+    <TextView
+        android:id="@+id/styled_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textSize="@dimen/text_size"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent"/>
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/ui/text/TextStyling-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..bbd3e02
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/ui/text/TextStyling-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..bbd3e02
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-hdpi/ic_launcher.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a2f5908
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..1b52399
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-mdpi/ic_launcher.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..ff10afd
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..115a4c7
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..dcd3cd8
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..459ca60
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..8ca12fe
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..8e19b41
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b824ebd
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..4c19a13
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Java/app/src/main/res/values/colors.xml b/ui/text/TextStyling-Java/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..dd5759d
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+    <color name="code_background">#BBBBBB</color>
+</resources>
diff --git a/ui/text/TextStyling-Java/app/src/main/res/values/dimens.xml b/ui/text/TextStyling-Java/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..255752f
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+<resources>
+    <dimen name="text_size">32sp</dimen>
+</resources>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/app/src/main/res/values/font_certs.xml b/ui/text/TextStyling-Java/app/src/main/res/values/font_certs.xml
new file mode 100644
index 0000000..6aff3b3
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/values/font_certs.xml
@@ -0,0 +1,32 @@
+<?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.
+  -->
+<resources>
+    <array name="com_google_android_gms_fonts_certs">
+        <item>@array/com_google_android_gms_fonts_certs_dev</item>
+        <item>@array/com_google_android_gms_fonts_certs_prod</item>
+    </array>
+    <string-array name="com_google_android_gms_fonts_certs_dev">
+        <item>
+            MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
+        </item>
+    </string-array>
+    <string-array name="com_google_android_gms_fonts_certs_prod">
+        <item>
+            MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
+        </item>
+    </string-array>
+</resources>
diff --git a/ui/text/TextStyling-Java/app/src/main/res/values/preloaded_fonts.xml b/ui/text/TextStyling-Java/app/src/main/res/values/preloaded_fonts.xml
new file mode 100644
index 0000000..b45fb89
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/values/preloaded_fonts.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+<resources>
+    <array name="preloaded_fonts" translatable="false">
+        <item>@font/inconsolata</item>
+    </array>
+</resources>
diff --git a/ui/text/TextStyling-Java/app/src/main/res/values/strings.xml b/ui/text/TextStyling-Java/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..335e1cb
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/values/strings.xml
@@ -0,0 +1,21 @@
+<!--
+~ 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.
+-->
+<resources>
+    <string name="app_name">TextStylingJava</string>
+    <string name="display_text">> Paragraphs starting with \">\" are quotes.
+        \nLines starting with * or + are bullet points:\n* Point one\n+ Point two, where nested
+        text enclosed in quotes is transformed in a `code` block</string>
+</resources>
diff --git a/ui/text/TextStyling-Java/app/src/main/res/values/styles.xml b/ui/text/TextStyling-Java/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..688f9e8
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/main/res/values/styles.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ 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.
+  -->
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+</resources>
diff --git a/ui/text/TextStyling-Java/app/src/test/java/com/android/example/text/styling/parser/ParserTest.java b/ui/text/TextStyling-Java/app/src/test/java/com/android/example/text/styling/parser/ParserTest.java
new file mode 100644
index 0000000..9dbbacd
--- /dev/null
+++ b/ui/text/TextStyling-Java/app/src/test/java/com/android/example/text/styling/parser/ParserTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.example.text.styling.parser;
+
+import static com.android.example.text.styling.parser.Element.Type.BULLET_POINT;
+import static com.android.example.text.styling.parser.Element.Type.CODE_BLOCK;
+import static com.android.example.text.styling.parser.Element.Type.QUOTE;
+import static com.android.example.text.styling.parser.Element.Type.TEXT;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * Tests for {@link Parser}
+ */
+public class ParserTest {
+
+    @Test
+    public void quoteBeginingOfText() {
+        String withQuote = "> This is a quote.\nThis is not";
+
+        List<Element> elements = new Parser().parse(withQuote).getElements();
+
+        assertEquals(elements.size(), 2);
+        assertEquals(elements.get(0).getType(), QUOTE);
+        assertEquals(elements.get(0).getText(), "This is a quote.\n");
+        assertEquals(elements.get(1).getType(), TEXT);
+        assertEquals(elements.get(1).getText(), "This is not");
+    }
+
+    @Test
+    public void quoteEndOfText() {
+        String withQuote = "This is not a quote.\n> This is a quote";
+
+        List<Element> elements = new Parser().parse(withQuote).getElements();
+
+        assertEquals(elements.size(), 2);
+        assertEquals(elements.get(0).getType(), TEXT);
+        assertEquals(elements.get(0).getText(), "This is not a quote.\n");
+        assertEquals(elements.get(1).getType(), QUOTE);
+        assertEquals(elements.get(1).getText(), "This is a quote");
+    }
+
+    @Test
+    public void simpleBulletPoints() {
+        String bulletPoints = "Bullet points:\n* One\n+ Two\n* Three";
+
+        List<Element> elements = new Parser().parse(bulletPoints).getElements();
+
+        assertEquals(elements.size(), 4);
+        assertEquals(elements.get(0).getType(), TEXT);
+        assertEquals(elements.get(0).getText(), "Bullet points:\n");
+        assertEquals(elements.get(1).getType(), BULLET_POINT);
+        assertEquals(elements.get(1).getText(), "One\n");
+        assertEquals(elements.get(2).getType(), BULLET_POINT);
+        assertEquals(elements.get(2).getText(), "Two\n");
+        assertEquals(elements.get(3).getType(), BULLET_POINT);
+        assertEquals(elements.get(3).getText(), "Three");
+    }
+
+    @Test
+    public void simpleCode() {
+        String code = "Styling `Text` in `Java`";
+
+        List<Element> elements = new Parser().parse(code).getElements();
+
+        assertEquals(elements.size(), 4);
+        assertEquals(elements.get(0).getType(), TEXT);
+        assertEquals(elements.get(0).getText(), "Styling ");
+        assertEquals(elements.get(1).getType(), CODE_BLOCK);
+        assertEquals(elements.get(1).getText(), "Text");
+        assertEquals(elements.get(2).getType(), TEXT);
+        assertEquals(elements.get(2).getText(), " in ");
+        assertEquals(elements.get(3).getType(), CODE_BLOCK);
+        assertEquals(elements.get(3).getText(), "Java");
+    }
+
+    @Test
+    public void codeWithExtraTick() {
+        String code = "Styling `Text` in `Java";
+
+        List<Element> elements = new Parser().parse(code).getElements();
+
+        assertEquals(elements.size(), 4);
+        assertEquals(elements.get(0).getType(), TEXT);
+        assertEquals(elements.get(0).getText(), "Styling ");
+        assertEquals(elements.get(1).getType(), CODE_BLOCK);
+        assertEquals(elements.get(1).getText(), "Text");
+        assertEquals(elements.get(2).getType(), TEXT);
+        assertEquals(elements.get(2).getText(), " in ");
+        assertEquals(elements.get(3).getType(), TEXT);
+        assertEquals(elements.get(3).getText(), "`Java");
+    }
+
+    @Test
+    public void quoteBulletPointsCode() {
+        String text = "Complex:\n> Quote\nWith points:\n+ bullet `one`\n* bullet `two` is `long`";
+
+        List<Element> elements = new Parser().parse(text).getElements();
+
+        assertEquals(elements.size(), 5);
+        assertEquals(elements.get(0).getType(), TEXT);
+        assertEquals(elements.get(0).getText(), "Complex:\n");
+        assertEquals(elements.get(1).getType(), QUOTE);
+        assertEquals(elements.get(1).getText(), "Quote\n");
+        assertEquals(elements.get(2).getType(), TEXT);
+        assertEquals(elements.get(2).getText(), "With points:\n");
+        // first bullet point
+        assertEquals(elements.get(3).getType(), BULLET_POINT);
+        assertEquals(elements.get(3).getText(), "bullet `one`\n");
+        List<Element> subElements1 = elements.get(3).getElements();
+        assertEquals(subElements1.size(), 3);
+        assertEquals(subElements1.get(0).getType(), TEXT);
+        assertEquals(subElements1.get(0).getText(), "bullet ");
+        assertEquals(subElements1.get(1).getType(), CODE_BLOCK);
+        assertEquals(subElements1.get(1).getText(), "one");
+        assertEquals(subElements1.get(2).getType(), TEXT);
+        assertEquals(subElements1.get(2).getText(), "\n");
+        // second bullet point
+        assertEquals(elements.get(4).getType(), BULLET_POINT);
+        assertEquals(elements.get(4).getText(), "bullet `two` is `long`");
+        List<Element> subElements2 = elements.get(4).getElements();
+        assertEquals(subElements2.size(), 4);
+        assertEquals(subElements2.get(0).getType(), TEXT);
+        assertEquals(subElements2.get(0).getText(), "bullet ");
+        assertEquals(subElements2.get(1).getType(), CODE_BLOCK);
+        assertEquals(subElements2.get(1).getText(), "two");
+        assertEquals(subElements2.get(2).getType(), TEXT);
+        assertEquals(subElements2.get(2).getText(), " is ");
+        assertEquals(subElements2.get(3).getType(), CODE_BLOCK);
+        assertEquals(subElements2.get(3).getText(), "long");
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Java/build.gradle b/ui/text/TextStyling-Java/build.gradle
new file mode 100644
index 0000000..fc0b4c8
--- /dev/null
+++ b/ui/text/TextStyling-Java/build.gradle
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+// Top-level build file where you can add configuration :options common to all sub-projects/modules.
+
+buildscript {
+
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
+
+// Define versions in a single place
+ext {
+    // Sdk and tools
+    minSdkVersion = 15
+    targetSdkVersion = 27
+    compileSdkVersion = 27
+    buildToolsVersion = '27.0.3'
+
+    // App dependencies
+    supportLibraryVersion = '27.0.2'
+    constraintLayoutVersion = '1.0.2'
+    junitVersion = '4.12'
+    mockitoVersion = '1.10.19'
+    hamcrestVersion = '1.3'
+    runnerVersion = '1.0.1'
+    rulesVersion = '1.0.1'
+    espressoVersion = '3.0.1'
+    dexmakerVersion = '1.2'
+    dexmakerMockitoVersion = '1.2'
+}
diff --git a/ui/text/TextStyling-Java/gradle.properties b/ui/text/TextStyling-Java/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/ui/text/TextStyling-Java/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/ui/text/TextStyling-Java/gradle/wrapper/gradle-wrapper.jar b/ui/text/TextStyling-Java/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/ui/text/TextStyling-Java/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/text/TextStyling-Java/gradle/wrapper/gradle-wrapper.properties b/ui/text/TextStyling-Java/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..69bc3cf
--- /dev/null
+++ b/ui/text/TextStyling-Java/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sun Jan 07 15:04:40 GMT 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/ui/text/TextStyling-Java/gradlew b/ui/text/TextStyling-Java/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/ui/text/TextStyling-Java/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/ui/text/TextStyling-Java/gradlew.bat b/ui/text/TextStyling-Java/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/ui/text/TextStyling-Java/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windowz variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+if "%@eval[2+2]" == "4" goto 4NT_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+goto execute

+

+:4NT_args

+@rem Get arguments from the 4NT Shell from JP Software

+set CMD_LINE_ARGS=%$

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/ui/text/TextStyling-Java/settings.gradle b/ui/text/TextStyling-Java/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/ui/text/TextStyling-Java/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/ui/text/TextStyling-Kotlin/.gitignore b/ui/text/TextStyling-Kotlin/.gitignore
new file mode 100644
index 0000000..0b39def
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+/projectFilesBackup
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/README.md b/ui/text/TextStyling-Kotlin/README.md
new file mode 100644
index 0000000..93f58e9
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/README.md
@@ -0,0 +1,73 @@
+Text Styling
+============
+This sample shows how to style text on Android using spans, in Kotlin, using [Android KTX](https://github.com/android/android-ktx).
+
+Introduction
+------------
+## Features
+Parse some hardcoded text and do the following:
+* Paragraphs starting with “> ” are transformed into quotes.
+* Text enclosed in “```” will be transformed into inline code block.
+* Lines starting with “+ ” or “* ” will be transformed into bullet points.
+To update the text, modify the value of `R.string.display_text`.
+This project is not meant to fully cover the markdown capabilities and has several limitations; for example, quotes do not support nesting other elements.
+
+## Implementation
+The text is parsed in the [`Parser.parse`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/parser/Parser.kt#L42) method and the spans are created in the [`MarkdownBuilder.markdownToSpans`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.kt#L43) method.
+To see how to apply one or multiple spans on a string, check out [`MarkdownBuilder.buildElement`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.kt#L53). For examples of creating custom spans, see [`BulletPointSpan`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/BulletPointSpan.kt), [`CodeBlockSpan`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/CodeBlockSpan.kt) or [`FontSpan`](https://github.com/googlesamples/android-text/blob/master/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/FontSpan.kt).
+
+## Testing
+Text parsing is tested with JUnit tests in `ParserTest`. Span building is tested via Android JUnit tests, in `MarkdownBuilderTest`.
+
+
+Getting Started
+---------------
+
+Clone this repository, enter the top level directory and run `./gradlew tasks`
+to get an overview of all the tasks available for this project.
+
+Some important tasks are:
+
+```
+assembleDebug - Assembles all Debug builds.
+installDebug - Installs the Debug build.
+connectedAndroidTest - Installs and runs the tests for Debug build on connected
+devices.
+test - Run all unit tests.
+```
+
+Screenshots
+-----------
+<img src="../screenshots/main_activity.png" width="30%" />
+
+Support
+-------
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android-text
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-text/issues
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub.
+
+License
+--------
+```
+Copyright 2018 The Android Open Source Project
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+```
+
diff --git a/ui/text/TextStyling-Kotlin/app/.gitignore b/ui/text/TextStyling-Kotlin/app/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/.gitignore
diff --git a/ui/text/TextStyling-Kotlin/app/build.gradle b/ui/text/TextStyling-Kotlin/app/build.gradle
new file mode 100644
index 0000000..075ac22
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/build.gradle
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion rootProject.compileSdkVersion
+    buildToolsVersion rootProject.buildToolsVersion
+
+    defaultConfig {
+        applicationId "com.android.example.text.styling"
+        minSdkVersion rootProject.minSdkVersion
+        targetSdkVersion rootProject.targetSdkVersion
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+    buildTypes {
+        release {
+            postprocessing {
+                removeUnusedCode false
+                removeUnusedResources false
+                obfuscate false
+                optimizeCode false
+                proguardFile 'proguard-rules.pro'
+            }
+        }
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
+    implementation "com.android.support.constraint:constraint-layout:$constraintLayoutVersion"
+
+    // Android KTX
+    implementation "androidx.core:core-ktx:$androidktx"
+
+    // Dependencies for local unit tests
+    testImplementation "junit:junit:$junitVersion"
+
+    androidTestImplementation "org.mockito:mockito-core:$mockitoVersion"
+    androidTestImplementation "com.android.support.test:runner:$runnerVersion"
+    androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
+    androidTestImplementation "com.google.dexmaker:dexmaker:$dexmakerVersion"
+    androidTestImplementation "com.google.dexmaker:dexmaker-mockito:$dexmakerMockitoVersion"
+
+    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
+
+repositories {
+    google()
+}
diff --git a/ui/text/TextStyling-Kotlin/app/proguard-rules.pro b/ui/text/TextStyling-Kotlin/app/proguard-rules.pro
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/proguard-rules.pro
diff --git a/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/MarkdownBuilderTest.kt b/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/MarkdownBuilderTest.kt
new file mode 100644
index 0000000..1ef82a8
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/MarkdownBuilderTest.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.example.text.styling.renderer
+
+import android.graphics.Typeface
+import android.support.test.InstrumentationRegistry
+import android.support.v4.content.res.ResourcesCompat
+import android.text.style.LeadingMarginSpan
+import android.text.style.RelativeSizeSpan
+import android.text.style.StyleSpan
+import com.android.example.text.styling.R
+import com.android.example.text.styling.parser.Parser
+import com.android.example.text.styling.renderer.spans.BulletPointSpan
+import com.android.example.text.styling.renderer.spans.CodeBlockSpan
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Tests for [MarkdownBuilder] class
+ */
+class MarkdownBuilderTest {
+
+    private val context = InstrumentationRegistry.getTargetContext()
+    private val bulletPointColor = context.getColor(R.color.colorAccent)
+    private val codeBackgroundColor = context.getColor(R.color.code_background)
+    private val codeBlockTypeface = ResourcesCompat.getFont(context, R.font.inconsolata)
+    private val builder = MarkdownBuilder(bulletPointColor, codeBackgroundColor, codeBlockTypeface,
+            Parser)
+
+    @Test fun builder() {
+        val result = builder.markdownToSpans("Hello, world!")
+        assertEquals("Hello, world!", result.toString())
+    }
+
+    @Test fun text() {
+        val result = builder.markdownToSpans("Text")
+
+        val spans = result.getSpans<Any>(0, result.length, Any::class.java)
+        assertEquals(0, spans.size.toLong())
+    }
+
+    @Test fun textWithQuote() {
+        val result = builder.markdownToSpans("Text\n> Quote")
+
+        assertEquals("Text\nQuote", result.toString())
+        val spans = result.getSpans<Any>(0, result.length, Any::class.java)
+        assertEquals(3, spans.size.toLong())
+
+        val styleSpan = spans[0] as StyleSpan
+        assertEquals(Typeface.ITALIC.toLong(), styleSpan.style.toLong())
+        assertEquals(5, result.getSpanStart(styleSpan).toLong())
+        assertEquals(10, result.getSpanEnd(styleSpan).toLong())
+        val leadingMarginSpan = spans[1] as LeadingMarginSpan
+        assertEquals(5, result.getSpanStart(leadingMarginSpan).toLong())
+        assertEquals(10, result.getSpanEnd(leadingMarginSpan).toLong())
+        val relativeSizeSpan = spans[2] as RelativeSizeSpan
+        assertEquals(5, result.getSpanStart(relativeSizeSpan).toLong())
+        assertEquals(10, result.getSpanEnd(relativeSizeSpan).toLong())
+    }
+
+    @Test fun textWithBulletPoints() {
+        val result = builder.markdownToSpans("Points\n* one\n+ two")
+
+        assertEquals("Points\none\ntwo", result.toString())
+        val spans = result.getSpans<Any>(0, result.length, Any::class.java)
+        assertEquals(2, spans.size.toLong())
+
+        val bulletSpan = spans[0] as BulletPointSpan
+        assertEquals(7, result.getSpanStart(bulletSpan).toLong())
+        assertEquals(11, result.getSpanEnd(bulletSpan).toLong())
+        val bulletSpan2 = spans[1] as BulletPointSpan
+        assertEquals(11, result.getSpanStart(bulletSpan2).toLong())
+        assertEquals(14, result.getSpanEnd(bulletSpan2).toLong())
+    }
+
+    @Test fun textWithCode() {
+        val result = builder.markdownToSpans("Text `code`")
+
+        assertEquals("Text code", result.toString())
+        val spans = result.getSpans<Any>(0, result.length, Any::class.java)
+        assertEquals(1, spans.size.toLong())
+
+        val codeSpan = spans[0] as CodeBlockSpan
+        assertEquals(5, result.getSpanStart(codeSpan).toLong())
+        assertEquals(9, result.getSpanEnd(codeSpan).toLong())
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/BulletPointSpanTest.kt b/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/BulletPointSpanTest.kt
new file mode 100644
index 0000000..09751ce
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/BulletPointSpanTest.kt
@@ -0,0 +1,102 @@
+package com.android.example.text.styling.renderer.spans
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.text.Layout
+import android.text.SpannableString
+import android.text.Spanned
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.mockito.Matchers
+import org.mockito.Matchers.eq
+import org.mockito.Mockito.*
+
+private const val GAP_WIDTH = 5
+
+class BulletPointSpanTest {
+
+    private val canvas = mock(Canvas::class.java)
+    private val paint = mock(Paint::class.java)
+    private val text = SpannableString("text")
+
+    @Test
+    fun getLeadingMargin() {
+        // Given a span with a certain gap width
+        val span = BulletPointSpan(GAP_WIDTH, 0)
+
+        // Check that the margin is set correctly
+        val expectedMargin = (2 * BulletPointSpan.DEFAULT_BULLET_RADIUS + 2 * GAP_WIDTH).toInt()
+        assertEquals(expectedMargin.toLong(), span.getLeadingMargin(true).toLong())
+    }
+
+    @Test
+    fun drawLeadingMarginWithoutText() {
+        // Given a span
+        val span = BulletPointSpan(GAP_WIDTH, 0)
+
+        // When the leading margin is drawn but no text is set
+        span.drawLeadingMargin(canvas, paint, 0, 0, 0, 0, 0, text, 0, 0, true,
+                mock(Layout::class.java))
+
+        // Check that no drawing methods are called
+        verifyZeroInteractions(canvas)
+        verifyZeroInteractions(paint)
+    }
+
+    @Test
+    fun drawLeadingMarginHardwareAccelerated() {
+        val x = 10
+        val dir = 15
+        val top = 5
+        val bottom = 7
+        val color = Color.RED
+        // Given a span that is set on a text
+        val span = BulletPointSpan(GAP_WIDTH, color)
+        text.setSpan(span, 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+        `when`(canvas.isHardwareAccelerated).thenReturn(true)
+
+        // When the leading margin is drawn
+        span.drawLeadingMargin(canvas, paint, x, dir, top, 0, bottom, text, 0, 0, true,
+                mock(Layout::class.java))
+
+        // Check that the correct canvas and paint methods are called, in the correct order
+        val inOrder = inOrder(canvas, paint)
+        inOrder.verify(paint).color = color
+        inOrder.verify(paint).style = eq<Paint.Style>(Paint.Style.FILL)
+        inOrder.verify(canvas).translate(
+                eq(GAP_WIDTH.toFloat() + x.toFloat() + dir * BulletPointSpan.DEFAULT_BULLET_RADIUS),
+                eq((top + bottom) / 2f))
+        inOrder.verify(canvas).drawPath(Matchers.any(Path::class.java), eq(paint))
+    }
+
+    @Test
+    fun drawLeadingMarginNotHardwareAccelerated() {
+        val x = 10
+        val dir = 15
+        val top = 5
+        val bottom = 7
+        val color = Color.RED
+        // Given a span that is set on a text
+        val span = BulletPointSpan(GAP_WIDTH, color)
+        text.setSpan(span, 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+        `when`(canvas.isHardwareAccelerated).thenReturn(false)
+
+        // When the leading margin is drawn
+        span.drawLeadingMargin(canvas, paint, x, dir, top, 0, bottom, text, 0, 0, true,
+                mock(Layout::class.java))
+
+        // Check that the correct canvas and paint methods are called, in the correct order
+        val inOrder = inOrder(canvas, paint)
+        inOrder.verify(paint).color = color
+        inOrder.verify(paint).style = eq<Paint.Style>(Paint.Style.FILL)
+        inOrder.verify(canvas).drawCircle(eq(GAP_WIDTH.toFloat() + x.toFloat()
+                + dir * BulletPointSpan.DEFAULT_BULLET_RADIUS),
+                eq((top + bottom) / 2f), eq(BulletPointSpan.DEFAULT_BULLET_RADIUS), eq(paint))
+        verify(canvas, never()).save()
+        verify(canvas, never()).translate(
+                eq(GAP_WIDTH.toFloat() + x.toFloat() + dir * BulletPointSpan.DEFAULT_BULLET_RADIUS),
+                eq((top + bottom) / 2f))
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/CodeBlockSpanTest.kt b/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/CodeBlockSpanTest.kt
new file mode 100644
index 0000000..528a565
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/CodeBlockSpanTest.kt
@@ -0,0 +1,27 @@
+package com.android.example.text.styling.renderer.spans
+
+import org.junit.Assert.assertEquals
+import org.mockito.Mockito.mock
+
+import android.graphics.Color
+import android.graphics.Typeface
+import android.text.TextPaint
+
+import org.junit.Test
+
+/**
+ * Tests for the [CodeBlockSpan] class
+ */
+class CodeBlockSpanTest {
+
+    private val paint = mock(TextPaint::class.java)
+    private val span = CodeBlockSpan(Typeface.DEFAULT, Color.RED)
+
+    @Test fun updateDrawState() {
+        // When the update draw state is called
+        span.updateDrawState(paint)
+
+        // Check that the correct color is set
+        assertEquals(Color.RED, paint.bgColor)
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/FontSpanTest.kt b/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/FontSpanTest.kt
new file mode 100644
index 0000000..2c46e91
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/androidTest/java/com/android/example/text/styling/renderer/spans/FontSpanTest.kt
@@ -0,0 +1,49 @@
+package com.android.example.text.styling.renderer.spans
+
+import junit.framework.Assert.assertEquals
+
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+
+import android.graphics.Typeface
+import android.text.TextPaint
+
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+
+/**
+ * Tests for the [FontSpan] class.
+ */
+class FontSpanTest {
+
+    private val paint = mock(TextPaint::class.java)
+    private val span = FontSpan(Typeface.DEFAULT)
+    private val defaultTypeface = Typeface.create("serif", Typeface.BOLD)
+
+    @Before fun setUp() {
+        `when`(paint.typeface).thenReturn(defaultTypeface)
+    }
+
+    @Test fun updateMeasureState() {
+        // When the update measure state is called
+        span.updateMeasureState(paint)
+
+        // Check that the typeface set has the correct typeface and style
+        val captor = ArgumentCaptor.forClass(Typeface::class.java)
+        verify(paint).typeface = captor.capture()
+        assertEquals(Typeface.BOLD, captor.value.style)
+    }
+
+    @Test fun updateDrawState() {
+        // When the update draw state is called
+        span.updateDrawState(paint)
+
+        // Check that the typeface set has the correct typeface and style
+        val captor = ArgumentCaptor.forClass(Typeface::class.java)
+        verify(paint).typeface = captor.capture()
+        assertEquals(Typeface.BOLD, captor.value.style)
+    }
+
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/AndroidManifest.xml b/ui/text/TextStyling-Kotlin/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..675a7bd
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.example.text.styling">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts"/>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/Extensions.kt b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/Extensions.kt
new file mode 100644
index 0000000..a6f84ad
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/Extensions.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.example.text.styling
+
+import android.content.Context
+import android.support.annotation.ColorRes
+import android.support.annotation.FontRes
+import android.support.v4.content.ContextCompat
+import android.support.v4.content.res.ResourcesCompat
+
+fun Context.getColorCompat(@ColorRes colorRes: Int) = ContextCompat.getColor(this, colorRes)
+fun Context.getFontCompat(@FontRes fontRes: Int) = ResourcesCompat.getFont(this, fontRes)
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/MainActivity.kt b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/MainActivity.kt
new file mode 100644
index 0000000..b35ff82
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/MainActivity.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.example.text.styling
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.widget.TextView
+import com.android.example.text.styling.parser.Parser
+import com.android.example.text.styling.renderer.MarkdownBuilder
+
+/**
+ * This sample demonstrates techniques for stying text; it is not intended to be a full markdown
+ * parser.
+ */
+class MainActivity : AppCompatActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+        // This is a simple markdown parser, where:
+        // Paragraphs starting with “> ” are transformed into quotes. Quotes can't contain
+        // other markdown elements
+        // Text enclosed in “`” will be transformed into inline code block
+        // Lines starting with “+ ” or “* ” will be transformed into bullet points. Bullet
+        // points can contain nested markdown elements, like code.
+        val bulletPointColor = getColorCompat(R.color.colorAccent)
+        val codeBackgroundColor = getColorCompat(R.color.code_background)
+        val codeBlockTypeface = getFontCompat(R.font.inconsolata)
+
+        MarkdownBuilder(bulletPointColor, codeBackgroundColor, codeBlockTypeface, Parser)
+                .markdownToSpans(getString(R.string.display_text))
+                .run { findViewById<TextView>(R.id.styledText).text = this }
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/parser/Markdown.kt b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/parser/Markdown.kt
new file mode 100644
index 0000000..a92dd2b
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/parser/Markdown.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.example.text.styling.parser
+
+/**
+ * Simple markdown parsing of text.
+ * Contains a list of markdown [Element]s
+ */
+data class TextMarkdown(val elements: List<Element>)
+
+/**
+ * Markdown like type of element.
+ */
+data class Element(val type: Type,
+                   val text: CharSequence,
+                   val elements: List<Element> = emptyList()
+) {
+
+    enum class Type {
+        TEXT, QUOTE, BULLET_POINT, CODE_BLOCK
+    }
+}
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/parser/Parser.kt b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/parser/Parser.kt
new file mode 100644
index 0000000..9ac4d1f
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/parser/Parser.kt
@@ -0,0 +1,158 @@
+/*
+ * 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.example.text.styling.parser
+
+import java.util.Collections.emptyList
+import java.util.regex.Pattern
+
+/**
+ * The role of this parser is just to showcase ways of working with text. It should not be
+ * expected to support complex markdown elements.
+ *
+ * Parse text and extract markdown elements:
+ *
+ *  * Paragraphs starting with “> ” are transformed into quotes. Quotes can't contain
+ * other markdown elements.
+ *  *  Text enclosed in “`” will be transformed into inline code block.
+ *  * Lines starting with “+ ” or “* ” will be transformed into bullet points. Bullet
+ * points can contain nested markdown elements, like code.
+ *
+ */
+object Parser {
+
+    /**
+     * Parse a text and extract the [TextMarkdown].
+     *
+     * @param string string to be parsed into markdown elements
+     * @return the [TextMarkdown]
+     */
+    fun parse(string: String): TextMarkdown {
+        val parents = mutableListOf<Element>()
+
+        val patternQuote = Pattern.compile(QUOTE_REGEX)
+        val pattern = Pattern.compile(BULLET_POINT_CODE_BLOCK_REGEX)
+
+        val matcher = patternQuote.matcher(string)
+        var lastStartIndex = 0
+
+        while (matcher.find(lastStartIndex)) {
+            val startIndex = matcher.start()
+            val endIndex = matcher.end()
+            // we found a quote
+            if (lastStartIndex < startIndex) {
+                // check what was before the quote
+                val text = string.subSequence(lastStartIndex, startIndex)
+                parents.addAll(findElements(text, pattern))
+            }
+            // a quote can only be a paragraph long, so look for end of line
+            val endOfQuote = getEndOfParagraph(string, endIndex)
+            lastStartIndex = endOfQuote
+            val quotedText = string.subSequence(endIndex, endOfQuote)
+            parents.add(Element(Element.Type.QUOTE, quotedText, emptyList<Element>()))
+        }
+
+        // check if there are any other element after the quote
+        if (lastStartIndex < string.length) {
+            val text = string.subSequence(lastStartIndex, string.length)
+            parents.addAll(findElements(text, pattern))
+        }
+
+        return TextMarkdown(parents)
+    }
+
+    private fun getEndOfParagraph(string: CharSequence, endIndex: Int): Int {
+        var endOfParagraph = string.indexOf(LINE_SEPARATOR, endIndex)
+        if (endOfParagraph == -1) {
+            // we don't have an end of line, so the quote is the last element in the text
+            // so we can consider that the end of the quote is the end of the text
+            endOfParagraph = string.length
+        } else {
+            // add the new line as part of the element
+            endOfParagraph++
+        }
+        return endOfParagraph
+    }
+
+    private fun findElements(string: CharSequence, pattern: Pattern): List<Element> {
+        val parents = mutableListOf<Element>()
+        val matcher = pattern.matcher(string)
+        var lastStartIndex = 0
+
+        while (matcher.find(lastStartIndex)) {
+            val startIndex = matcher.start()
+            val endIndex = matcher.end()
+            // we found a mark
+            val mark = string.subSequence(startIndex, endIndex)
+            if (lastStartIndex < startIndex) {
+                // check what was before the mark
+                parents.addAll(findElements(string.subSequence(lastStartIndex, startIndex),
+                        pattern))
+            }
+            val text: CharSequence
+            // check what kind of mark this was
+            when (mark) {
+                BULLET_PLUS, BULLET_STAR -> {
+                    // every bullet point is max until a new line or end of text
+                    var endOfBulletPoint = getEndOfParagraph(string, endIndex)
+                    text = string.subSequence(endIndex, endOfBulletPoint)
+                    lastStartIndex = endOfBulletPoint
+                    // also see what else we have in the text
+                    val subMarks = findElements(text, pattern)
+                    val bulletPoint = Element(Element.Type.BULLET_POINT, text, subMarks)
+                    parents.add(bulletPoint)
+                }
+                CODE_BLOCK -> {
+                    // a code block is set between two "`" so look for the other one
+                    // if another "`" is not found, then this is not a code block
+                    var markEnd = string.indexOf(CODE_BLOCK, endIndex)
+                    if (markEnd == -1) {
+                        // we don't have an end of code block so this is just text
+                        markEnd = string.length
+                        text = string.substring(startIndex, markEnd)
+                        parents.add(Element(Element.Type.TEXT, text, emptyList()))
+                        lastStartIndex = markEnd
+                    } else {
+                        // we found the end of the code block
+                        text = string.substring(endIndex, markEnd)
+                        parents.add(Element(Element.Type.CODE_BLOCK, text,
+                                kotlin.collections.emptyList()))
+                        // adding 1 so we can ignore the ending "`" for the code block
+                        lastStartIndex = markEnd + 1
+                    }
+                }
+            }
+        }
+
+        // check if there's any more text left
+        if (lastStartIndex < string.length) {
+            val text = string.subSequence(lastStartIndex, string.length)
+            parents.add(Element(Element.Type.TEXT, text, emptyList<Element>()))
+        }
+
+        return parents
+    }
+
+    private const val BULLET_PLUS = "+ "
+    private const val BULLET_STAR = "* "
+    private const val QUOTE_REGEX = "(?m)^> "
+    private const val BULLET_POINT_STAR = "(?m)^\\$BULLET_STAR"
+    private const val BULLET_POINT_PLUS = "(?m)^\\$BULLET_PLUS"
+    private const val BULLET_POINT_REGEX = "($BULLET_POINT_STAR|$BULLET_POINT_PLUS)"
+    private const val CODE_BLOCK = "`"
+    private const val BULLET_POINT_CODE_BLOCK_REGEX = "($BULLET_POINT_REGEX|$CODE_BLOCK)"
+
+    private val LINE_SEPARATOR = System.getProperty("line.separator")
+}
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.kt b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.kt
new file mode 100644
index 0000000..b885f54
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/MarkdownBuilder.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.example.text.styling.renderer
+
+import android.graphics.Typeface
+import android.support.annotation.ColorInt
+import android.text.SpannableStringBuilder
+import android.text.SpannedString
+import android.text.style.LeadingMarginSpan
+import android.text.style.RelativeSizeSpan
+import android.text.style.StyleSpan
+import androidx.text.buildSpannedString
+import androidx.text.inSpans
+import com.android.example.text.styling.parser.Element
+import com.android.example.text.styling.parser.Parser
+import com.android.example.text.styling.renderer.spans.BulletPointSpan
+import com.android.example.text.styling.renderer.spans.CodeBlockSpan
+
+/**
+ * Renders the text as simple markdown, using spans.
+ */
+class MarkdownBuilder(
+        @ColorInt private val bulletPointColor: Int,
+        @ColorInt private val codeBackgroundColor: Int,
+        private val codeBlockTypeface: Typeface?,
+        private val parser: Parser
+) {
+
+    fun markdownToSpans(string: String): SpannedString {
+        val markdown = parser.parse(string)
+
+        return buildSpannedString {
+            markdown.elements.forEach { it -> buildElement(it, this) }
+        }
+    }
+
+    private fun buildElement(element: Element, builder: SpannableStringBuilder): CharSequence {
+        return builder.apply {
+            // apply different spans depending on the type of the element
+            when (element.type) {
+                Element.Type.CODE_BLOCK -> {
+                    inSpans(CodeBlockSpan(codeBlockTypeface, codeBackgroundColor)) {
+                        append(element.text)
+                    }
+                }
+                Element.Type.QUOTE -> {
+                    // You can set multiple spans for the same text
+                    inSpans(StyleSpan(Typeface.ITALIC),
+                            LeadingMarginSpan.Standard(40),
+                            RelativeSizeSpan(1.1f)) {
+                        append(element.text)
+                    }
+                }
+                Element.Type.BULLET_POINT -> {
+                    inSpans(BulletPointSpan(20, bulletPointColor)) {
+                        for (child in element.elements) {
+                            buildElement(child, builder)
+                        }
+                    }
+                }
+                Element.Type.TEXT -> append(element.text)
+            }
+        }
+    }
+
+}
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/BulletPointSpan.kt b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/BulletPointSpan.kt
new file mode 100644
index 0000000..13bd16e
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/BulletPointSpan.kt
@@ -0,0 +1,115 @@
+/*
+ * 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.example.text.styling.renderer.spans
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.Path.Direction
+import android.support.annotation.ColorInt
+import android.support.annotation.Px
+import android.support.annotation.VisibleForTesting
+import android.text.Layout
+import android.text.Spanned
+import android.text.style.LeadingMarginSpan
+import androidx.graphics.withTranslation
+
+/**
+ * Creating a bullet span with bigger bullets than [android.text.style.BulletSpan]
+ * and with a left margin.
+ */
+class BulletPointSpan(
+        @Px private val gapWidth: Int = DEFAULT_GAP_WIDTH,
+        @ColorInt private val color: Int = Color.BLACK,
+        private val useColor: Boolean = color != Color.BLACK
+) : LeadingMarginSpan {
+
+    // By default, lazy is thread safe. This is good if this property can be accessed from different
+    // threads, but impacts performance otherwise. As this property is initialized in a draw method,
+    // it's important to be as fast as possible.
+    private val bulletPath: Path by lazy(LazyThreadSafetyMode.NONE) { Path() }
+
+    override fun getLeadingMargin(first: Boolean): Int {
+        return (2 * DEFAULT_BULLET_RADIUS + 2 * gapWidth).toInt()
+    }
+
+    /**
+     * Using a similar drawing mechanism with [android.text.style.BulletSpan] but adding
+     * margins before the bullet.
+     */
+    override fun drawLeadingMargin(
+            canvas: Canvas, paint: Paint, currentMarginLocation: Int, paragraphDirection: Int,
+            lineTop: Int, lineBaseline: Int, lineBottom: Int, text: CharSequence, lineStart: Int,
+            lineEnd: Int, isFirstLine: Boolean, layout: Layout
+    ) {
+        if ((text as Spanned).getSpanStart(this) == lineStart) {
+            paint.withCustomColor {
+                if (canvas.isHardwareAccelerated) {
+                    // Bullet is slightly better to avoid aliasing artifacts on mdpi devices.
+                    bulletPath.addCircle(0.0f, 0.0f, 1.2f * DEFAULT_BULLET_RADIUS, Direction.CW)
+
+                    canvas.withTranslation(
+                            getCircleXLocation(currentMarginLocation, paragraphDirection),
+                            getCircleYLocation(lineTop, lineBottom)
+                    ) {
+                        drawPath(bulletPath, paint)
+                    }
+                } else {
+                    canvas.drawCircle(
+                            getCircleXLocation(currentMarginLocation, paragraphDirection),
+                            getCircleYLocation(lineTop, lineBottom),
+                            DEFAULT_BULLET_RADIUS,
+                            paint
+                    )
+                }
+            }
+        }
+    }
+
+    private fun getCircleYLocation(lineTop: Int, lineBottom: Int) =
+            (lineTop + lineBottom) / 2.0f
+
+    private fun getCircleXLocation(currentMarginLocation: Int, paragraphDirection: Int) =
+            gapWidth + currentMarginLocation + paragraphDirection * DEFAULT_BULLET_RADIUS
+
+    companion object {
+        private const val DEFAULT_GAP_WIDTH = 2
+        @VisibleForTesting
+        const val DEFAULT_BULLET_RADIUS = 15.0f
+    }
+
+    // When a custom color is used for bullets, the default style and colors need to be saved to
+    // then be set again after the draw finishes. This extension hides the boilerplate.
+    private inline fun Paint.withCustomColor(block: () -> Unit) {
+        val oldStyle = style
+        val oldColor = if (useColor) color else Color.TRANSPARENT
+
+        if (useColor) {
+            color = this@BulletPointSpan.color
+        }
+
+        style = Paint.Style.FILL
+
+        block()
+
+        if (useColor) {
+            color = oldColor
+        }
+
+        style = oldStyle
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/CodeBlockSpan.kt b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/CodeBlockSpan.kt
new file mode 100644
index 0000000..5cf7cf3
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/CodeBlockSpan.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.example.text.styling.renderer.spans
+
+import android.graphics.Color
+import android.graphics.Typeface
+import android.support.annotation.ColorInt
+import android.text.TextPaint
+import android.text.style.BackgroundColorSpan
+
+/**
+ * To draw a code block, we set a font for the text and a background color.
+ *
+ * The same effect can be achieved if on a text block, we set two spans: [FontSpan] and
+ * [BackgroundColorSpan]
+ */
+class CodeBlockSpan(
+        font: Typeface?,
+        @param:ColorInt private val backgroundColor: Int = Color.LTGRAY
+) : FontSpan(font) {
+
+    // Since we're only changing the background color, it will not affect the measure state, so
+    // just override the update draw state.
+    override fun updateDrawState(textPaint: TextPaint) {
+        super.updateDrawState(textPaint)
+        textPaint.bgColor = backgroundColor
+    }
+}
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/FontSpan.kt b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/FontSpan.kt
new file mode 100644
index 0000000..53fd11b
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/java/com/android/example/text/styling/renderer/spans/FontSpan.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.example.text.styling.renderer.spans
+
+import android.graphics.Typeface
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+
+/**
+ * Span that changes the typeface of the text used to the one provided. The style set before will
+ * be kept.
+ */
+open class FontSpan(private val font: Typeface?) : MetricAffectingSpan() {
+
+    override fun updateMeasureState(textPaint: TextPaint) = update(textPaint)
+
+    override fun updateDrawState(textPaint: TextPaint) = update(textPaint)
+
+    private fun update(textPaint: TextPaint) {
+        textPaint.apply {
+            val old = typeface
+            val oldStyle = old?.style ?: 0
+
+            // keep the style set before
+            val font = Typeface.create(font, oldStyle)
+            typeface = font
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..f6cd551
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,49 @@
+<!--
+  ~ 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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:aapt="http://schemas.android.com/aapt"
+        android:width="108dp"
+        android:height="108dp"
+        android:viewportHeight="108"
+        android:viewportWidth="108">
+    <path
+        android:fillType="evenOdd"
+        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+        android:strokeColor="#00000000"
+        android:strokeWidth="1">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="78.5885"
+                android:endY="90.9159"
+                android:startX="48.7653"
+                android:startY="61.0927"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0"/>
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0"/>
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+        android:strokeColor="#00000000"
+        android:strokeWidth="1"/>
+</vector>
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/drawable/ic_launcher_background.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..4f5b4fd
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,89 @@
+<?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.
+  -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportHeight="108"
+    android:viewportWidth="108">
+    <path android:fillColor="#26A69A"
+          android:pathData="M0,0h108v108h-108z"/>
+    <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,0L29,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,0L39,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,0L49,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,0L59,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,0L69,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,0L79,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M89,0L89,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M99,0L99,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,9L108,9"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,19L108,19"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,29L108,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,39L108,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,49L108,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,59L108,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,69L108,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,79L108,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,89L108,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,99L108,99"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,29L89,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,39L89,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,49L89,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,59L89,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,69L89,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,79L89,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,19L29,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,19L39,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,19L49,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,19L59,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+</vector>
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/font/inconsolata.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/font/inconsolata.xml
new file mode 100644
index 0000000..43f3d61
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/font/inconsolata.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ 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.
+  -->
+<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
+             app:fontProviderAuthority="com.google.android.gms.fonts"
+             app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"
+             app:fontProviderPackage="com.google.android.gms"
+             app:fontProviderQuery="Inconsolata">
+</font-family>
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/layout/activity_main.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..e956de5
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,35 @@
+<?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.
+  -->
+<android.support.constraint.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=".MainActivity">
+
+    <TextView
+        android:id="@+id/styledText"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:textSize="@dimen/text_size"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent"/>
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..bbd3e02
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..bbd3e02
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-hdpi/ic_launcher.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a2f5908
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..1b52399
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-mdpi/ic_launcher.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..ff10afd
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..115a4c7
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..dcd3cd8
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..459ca60
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..8ca12fe
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..8e19b41
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b824ebd
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..4c19a13
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/values/colors.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..dd5759d
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+    <color name="code_background">#BBBBBB</color>
+</resources>
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/values/dimens.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..255752f
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+<resources>
+    <dimen name="text_size">32sp</dimen>
+</resources>
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/values/font_certs.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/values/font_certs.xml
new file mode 100644
index 0000000..6aff3b3
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/values/font_certs.xml
@@ -0,0 +1,32 @@
+<?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.
+  -->
+<resources>
+    <array name="com_google_android_gms_fonts_certs">
+        <item>@array/com_google_android_gms_fonts_certs_dev</item>
+        <item>@array/com_google_android_gms_fonts_certs_prod</item>
+    </array>
+    <string-array name="com_google_android_gms_fonts_certs_dev">
+        <item>
+            MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
+        </item>
+    </string-array>
+    <string-array name="com_google_android_gms_fonts_certs_prod">
+        <item>
+            MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
+        </item>
+    </string-array>
+</resources>
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/values/preloaded_fonts.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/values/preloaded_fonts.xml
new file mode 100644
index 0000000..b45fb89
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/values/preloaded_fonts.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+<resources>
+    <array name="preloaded_fonts" translatable="false">
+        <item>@font/inconsolata</item>
+    </array>
+</resources>
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/values/strings.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..ed3bbf0
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/values/strings.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ 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.
+  -->
+<resources>
+    <string name="app_name">TextStyling</string>
+    <string name="display_text">> Paragraphs starting with \"\>" are quotes.
+        \nLines starting with * or + are bullet points:\n* Point one\n+ Point two, where nested
+        text enclosed in quotes is transformed in `code` block</string>
+</resources>
diff --git a/ui/text/TextStyling-Kotlin/app/src/main/res/values/styles.xml b/ui/text/TextStyling-Kotlin/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..1dcac05
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/main/res/values/styles.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ 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.
+  -->
+<resources>
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+</resources>
diff --git a/ui/text/TextStyling-Kotlin/app/src/test/java/com/android/example/text/styling/parser/ParserTest.kt b/ui/text/TextStyling-Kotlin/app/src/test/java/com/android/example/text/styling/parser/ParserTest.kt
new file mode 100644
index 0000000..ae8b67d
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/app/src/test/java/com/android/example/text/styling/parser/ParserTest.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.example.text.styling.parser
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Tests for [Parser]
+ */
+class ParserTest {
+
+    @Test fun quoteBeginningOfText() {
+        val withQuote = "> This is a quote.\nThis is not"
+
+        val elements = Parser.parse(withQuote).elements
+
+        val expected = listOf(
+                Element(Element.Type.QUOTE, "This is a quote.\n"),
+                Element(Element.Type.TEXT, "This is not"))
+        assertEquals(expected, elements)
+    }
+
+    @Test fun quoteEndOfText() {
+        val withQuote = "This is not a quote.\n> This is a quote"
+
+        val elements = Parser.parse(withQuote).elements
+
+        val expected = listOf(
+                Element(Element.Type.TEXT, "This is not a quote.\n"),
+                Element(Element.Type.QUOTE, "This is a quote"))
+        assertEquals(expected, elements)
+    }
+
+    @Test fun simpleBulletPoints() {
+        val bulletPoints = "Bullet points:\n* One\n+ Two\n* Three"
+
+        val elements = Parser.parse(bulletPoints).elements
+
+        assertEquals(elements.size, 4)
+        assertEquals(elements[0].type, Element.Type.TEXT)
+        assertEquals(elements[0].text, "Bullet points:\n")
+        assertEquals(elements[1].type, Element.Type.BULLET_POINT)
+        assertEquals(elements[1].text, "One\n")
+        assertEquals(elements[2].type, Element.Type.BULLET_POINT)
+        assertEquals(elements[2].text, "Two\n")
+        assertEquals(elements[3].type, Element.Type.BULLET_POINT)
+        assertEquals(elements[3].text, "Three")
+    }
+
+    @Test fun simpleCode() {
+        val code = "Styling `Text` in `Kotlin`"
+
+        val elements = Parser.parse(code).elements
+
+        val expected = listOf(
+                Element(Element.Type.TEXT, "Styling "),
+                Element(Element.Type.CODE_BLOCK, "Text"),
+                Element(Element.Type.TEXT, " in "),
+                Element(Element.Type.CODE_BLOCK, "Kotlin"))
+        assertEquals(expected, elements)
+    }
+
+    @Test fun codeWithExtraTick() {
+        val code = "Styling `Text` in `Kotlin"
+
+        val elements = Parser.parse(code).elements
+
+        val expected = listOf(
+                Element(Element.Type.TEXT, "Styling "),
+                Element(Element.Type.CODE_BLOCK, "Text"),
+                Element(Element.Type.TEXT, " in "),
+                Element(Element.Type.TEXT, "`Kotlin"))
+        assertEquals(expected, elements)
+    }
+
+    @Test fun quoteBulletPointsCode() {
+        val text = "Complex:\n> Quote\nWith points:\n+ bullet `one`\n* bullet `two` is `long`"
+
+        val elements = Parser.parse(text).elements
+
+        assertEquals(elements.size, 5)
+        assertEquals(elements[0].type, Element.Type.TEXT)
+        assertEquals(elements[0].text, "Complex:\n")
+        assertEquals(elements[1].type, Element.Type.QUOTE)
+        assertEquals(elements[1].text, "Quote\n")
+        assertEquals(elements[2].type, Element.Type.TEXT)
+        assertEquals(elements[2].text, "With points:\n")
+        // first bullet point
+        assertEquals(elements[3].type, Element.Type.BULLET_POINT)
+        assertEquals(elements[3].text, "bullet `one`\n")
+        val subElements1 = elements[3].elements
+        assertEquals(subElements1.size, 3)
+        assertEquals(subElements1[0].type, Element.Type.TEXT)
+        assertEquals(subElements1[0].text, "bullet ")
+        assertEquals(subElements1[1].type, Element.Type.CODE_BLOCK)
+        assertEquals(subElements1[1].text, "one")
+        assertEquals(subElements1[2].type, Element.Type.TEXT)
+        assertEquals(subElements1[2].text, "\n")
+        // second bullet point
+        assertEquals(elements[4].type, Element.Type.BULLET_POINT)
+        assertEquals(elements[4].text, "bullet `two` is `long`")
+        val subElements2 = elements[4].elements
+        assertEquals(subElements2.size, 4)
+        assertEquals(subElements2[0].type, Element.Type.TEXT)
+        assertEquals(subElements2[0].text, "bullet ")
+        assertEquals(subElements2[1].type, Element.Type.CODE_BLOCK)
+        assertEquals(subElements2[1].text, "two")
+        assertEquals(subElements2[2].type, Element.Type.TEXT)
+        assertEquals(subElements2[2].text, " is ")
+        assertEquals(subElements2[3].type, Element.Type.CODE_BLOCK)
+        assertEquals(subElements2[3].text, "long")
+    }
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/build.gradle b/ui/text/TextStyling-Kotlin/build.gradle
new file mode 100644
index 0000000..20f3b4c
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/build.gradle
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    ext.kotlin_version = '1.2.10'
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
+
+// Define versions in a single place
+ext {
+    // Sdk and tools
+    minSdkVersion = 15
+    targetSdkVersion = 27
+    compileSdkVersion = 27
+    buildToolsVersion = '27.0.2'
+
+    // App dependencies
+    supportLibraryVersion = '27.0.2'
+    constraintLayoutVersion = '1.0.2'
+    junitVersion = '4.12'
+    mockitoVersion = '1.10.19'
+    hamcrestVersion = '1.3'
+    runnerVersion = '1.0.1'
+    rulesVersion = '1.0.1'
+    espressoVersion = '3.0.1'
+    androidktx = "0.2"
+    dexmakerVersion = '1.2'
+    dexmakerMockitoVersion = '1.2'
+}
\ No newline at end of file
diff --git a/ui/text/TextStyling-Kotlin/gradle.properties b/ui/text/TextStyling-Kotlin/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/ui/text/TextStyling-Kotlin/gradle/wrapper/gradle-wrapper.jar b/ui/text/TextStyling-Kotlin/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/text/TextStyling-Kotlin/gradle/wrapper/gradle-wrapper.properties b/ui/text/TextStyling-Kotlin/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..62bde4b
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jan 08 15:27:50 GMT 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip
diff --git a/ui/text/TextStyling-Kotlin/gradlew b/ui/text/TextStyling-Kotlin/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/ui/text/TextStyling-Kotlin/gradlew.bat b/ui/text/TextStyling-Kotlin/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windowz variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+if "%@eval[2+2]" == "4" goto 4NT_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+goto execute

+

+:4NT_args

+@rem Get arguments from the 4NT Shell from JP Software

+set CMD_LINE_ARGS=%$

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/ui/text/TextStyling-Kotlin/settings.gradle b/ui/text/TextStyling-Kotlin/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/ui/text/TextStyling-Kotlin/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/ui/text/screenshots/icon-web.png b/ui/text/screenshots/icon-web.png
new file mode 100644
index 0000000..47f96e4
--- /dev/null
+++ b/ui/text/screenshots/icon-web.png
Binary files differ
diff --git a/ui/text/screenshots/main_activity.png b/ui/text/screenshots/main_activity.png
new file mode 100644
index 0000000..366b19f
--- /dev/null
+++ b/ui/text/screenshots/main_activity.png
Binary files differ
diff --git a/ui/transition/AdapterTransition/gradle/wrapper/gradle-wrapper.properties b/ui/transition/AdapterTransition/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/transition/AdapterTransition/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/transition/AdapterTransition/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/transition/BasicTransition/gradle/wrapper/gradle-wrapper.properties b/ui/transition/BasicTransition/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/transition/BasicTransition/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/transition/BasicTransition/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/transition/CustomTransition/gradle/wrapper/gradle-wrapper.properties b/ui/transition/CustomTransition/gradle/wrapper/gradle-wrapper.properties
index dd20b9a..a3c0811 100644
--- a/ui/transition/CustomTransition/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/transition/CustomTransition/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/transition/FragmentTransition/gradle/wrapper/gradle-wrapper.properties b/ui/transition/FragmentTransition/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/transition/FragmentTransition/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/transition/FragmentTransition/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/CardView/.google/packaging.yaml b/ui/views/CardView/.google/packaging.yaml
new file mode 100644
index 0000000..bc80878
--- /dev/null
+++ b/ui/views/CardView/.google/packaging.yaml
@@ -0,0 +1,16 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [UI]
+languages:    [Java]
+solutions:    [Mobile]
+github:       android-CardView
+level:        INTERMEDIATE
+icon:         CardViewSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+doc_refs:
+    - android:preview/material/ui-widgets.html
+license: apache2
diff --git a/ui/views/CardView/gradle/wrapper/gradle-wrapper.properties b/ui/views/CardView/gradle/wrapper/gradle-wrapper.properties
index 76ffa7b..349ecb6 100644
--- a/ui/views/CardView/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/CardView/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/CardView/kotlinApp/.google/packaging.yaml b/ui/views/CardView/kotlinApp/.google/packaging.yaml
new file mode 100644
index 0000000..97cd78a
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/.google/packaging.yaml
@@ -0,0 +1,13 @@
+
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [UI]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-CardView
+license:      apache2
diff --git a/ui/views/CardView/kotlinApp/Application/build.gradle b/ui/views/CardView/kotlinApp/Application/build.gradle
new file mode 100644
index 0000000..f9ba008
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/build.gradle
@@ -0,0 +1,36 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion rootProject.ext.compileSdkVersion
+    defaultConfig {
+        applicationId "com.example.android.cardview"
+        minSdkVersion rootProject.ext.minSdkVersion
+        targetSdkVersion rootProject.ext.targetSdkVersion
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+
+    sourceSets {
+        main {
+            java.srcDirs "src/main/java"
+            res.srcDirs "src/main/res"
+        }
+        androidTest.setRoot('tests')
+        androidTest.java.srcDirs = ['tests/src']
+    }
+}
+
+dependencies {
+    implementation'com.android.support:cardview-v7:27.0.2'
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
+    androidTestImplementation "com.android.support.test.espresso:espresso-core:$rootProject.ext.espressoVersion"
+}
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/AndroidManifest.xml b/ui/views/CardView/kotlinApp/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7d1145c
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.cardview">
+
+    <application
+        android:allowBackup="false"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".CardViewActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/java/com/example/android/cardview/CardViewActivity.kt b/ui/views/CardView/kotlinApp/Application/src/main/java/com/example/android/cardview/CardViewActivity.kt
new file mode 100644
index 0000000..4c90f0e
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/java/com/example/android/cardview/CardViewActivity.kt
@@ -0,0 +1,37 @@
+/*
+ * 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 com.example.android.cardview
+
+import android.app.Activity
+import android.os.Bundle
+
+/**
+ * Launcher Activity for the CardView sample app.
+ */
+class CardViewActivity : Activity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_card_view)
+        if (savedInstanceState == null) {
+            fragmentManager.beginTransaction()
+                    .add(R.id.container, CardViewFragment())
+                    .commit()
+        }
+    }
+
+}
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/java/com/example/android/cardview/CardViewFragment.kt b/ui/views/CardView/kotlinApp/Application/src/main/java/com/example/android/cardview/CardViewFragment.kt
new file mode 100644
index 0000000..6efb5aa
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/java/com/example/android/cardview/CardViewFragment.kt
@@ -0,0 +1,82 @@
+/*
+ * 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 com.example.android.cardview
+
+import android.app.Fragment
+import android.os.Bundle
+import android.support.annotation.VisibleForTesting
+import android.support.v7.widget.CardView
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.SeekBar
+
+/**
+ * Fragment that demonstrates how to use [CardView].
+ */
+class CardViewFragment : Fragment() {
+
+    private val TAG = "CardViewFragment"
+
+    // The [CardView] widget.
+    @VisibleForTesting lateinit var cardView: CardView
+
+    // SeekBar that changes the cornerRadius attribute for the cardView widget.
+    @VisibleForTesting lateinit var radiusSeekBar: SeekBar
+
+    // SeekBar that changes the Elevation attribute for the cardView widget.
+    @VisibleForTesting lateinit var elevationSeekBar: SeekBar
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        return inflater.inflate(R.layout.fragment_card_view, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        cardView = view.findViewById(R.id.cardview)
+
+        radiusSeekBar = view.findViewById(R.id.cardview_radius_seekbar)
+        radiusSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
+            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+                Log.d(TAG, "SeekBar Radius progress: $progress")
+                cardView.radius = progress.toFloat()
+            }
+
+            override fun onStartTrackingTouch(seekBar: SeekBar) = Unit // Do nothing
+
+            override fun onStopTrackingTouch(seekBar: SeekBar) = Unit // Do nothing
+        })
+
+        elevationSeekBar = view.findViewById(R.id.cardview_elevation_seekbar)
+        elevationSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
+            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+                Log.d(TAG, "SeekBar Elevation progress : $progress")
+                cardView.elevation = progress.toFloat()
+            }
+
+            override fun onStartTrackingTouch(seekBar: SeekBar) = Unit // Do nothing
+
+            override fun onStopTrackingTouch(seekBar: SeekBar) = Unit // Do nothing
+        })
+    }
+
+}
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..36f4db5
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f4ca065
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6464a93
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..5a017ba
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/layout/activity_card_view.xml b/ui/views/CardView/kotlinApp/Application/src/main/res/layout/activity_card_view.xml
new file mode 100644
index 0000000..86deaee
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/layout/activity_card_view.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    tools:context="com.example.android.cardview.CardViewActivity"
+    tools:ignore="MergeRootFrame" />
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/layout/fragment_card_view.xml b/ui/views/CardView/kotlinApp/Application/src/main/res/layout/fragment_card_view.xml
new file mode 100644
index 0000000..b43acb8
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/layout/fragment_card_view.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:card_view="http://schemas.android.com/apk/res-auto"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <LinearLayout android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingBottom="@dimen/activity_vertical_margin"
+        android:paddingTop="@dimen/activity_vertical_margin"
+        android:paddingLeft="@dimen/activity_horizontal_margin"
+        android:paddingRight="@dimen/activity_horizontal_margin">
+
+        <android.support.v7.widget.CardView
+            android:id="@+id/cardview"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:elevation="@dimen/card_elevation"
+            card_view:cardBackgroundColor="@color/cardview_initial_background"
+            card_view:cardCornerRadius="@dimen/card_radius"
+            android:layout_marginLeft="@dimen/margin_large"
+            android:layout_marginRight="@dimen/margin_large">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/margin_medium"
+                android:text="@string/cardview_contents"/>
+
+        </android.support.v7.widget.CardView>
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/margin_large"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="@dimen/seekbar_label_length"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:text="@string/cardview_radius_seekbar_text" />
+
+            <SeekBar
+                android:id="@+id/cardview_radius_seekbar"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/margin_medium"/>
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="@dimen/seekbar_label_length"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:text="@string/cardview_elevation_seekbar_text"/>
+
+            <SeekBar
+                android:id="@+id/cardview_elevation_seekbar"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/margin_medium"/>
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</ScrollView>
+
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/values/colors.xml b/ui/views/CardView/kotlinApp/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..5dfd57c
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <color name="cardview_initial_background">#71C3DE</color>
+</resources>
\ No newline at end of file
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/values/dimens.xml b/ui/views/CardView/kotlinApp/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..dbe7f04
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/values/dimens.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="seekbar_label_length">70dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="card_elevation">100dp</dimen>
+    <dimen name="card_radius">8dp</dimen>
+</resources>
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/values/strings.xml b/ui/views/CardView/kotlinApp/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..190c3f6
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/values/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <string name="app_name">CardView Sample</string>
+    <string name="cardview_contents">This is a CardView widget. CardView widgets can have
+        shadows and rounded corners.
+        \n\nTo create a card with a shadow, use the <font fgcolor="#FFFFFFFF">android:elevation</font>
+        attribute.
+        \n\nTo set the corner radius in your layouts, use the <font
+            fgcolor="#FFFFFFFF">card_view:cardCornerRadius</font> attribute.
+    </string>
+    <string name="cardview_radius_seekbar_text">Radius</string>
+    <string name="cardview_elevation_seekbar_text">Elevation</string>
+    <string name="intro_message">
+        <![CDATA[
+
+
+            This sample demonstrates how to use CardView introduced in the support library in
+            Android 5.0.
+
+
+        ]]>
+    </string>
+</resources>
diff --git a/ui/views/CardView/kotlinApp/Application/src/main/res/values/styles.xml b/ui/views/CardView/kotlinApp/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..7948848
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <style name="AppTheme" parent="android:Theme.Material.Light" />
+</resources>
\ No newline at end of file
diff --git a/ui/views/CardView/kotlinApp/Application/tests/src/com/example/android/cardview/SampleTests.kt b/ui/views/CardView/kotlinApp/Application/tests/src/com/example/android/cardview/SampleTests.kt
new file mode 100644
index 0000000..df46390
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/Application/tests/src/com/example/android/cardview/SampleTests.kt
@@ -0,0 +1,69 @@
+/*
+ * 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 com.example.android.cardview
+
+import android.support.test.InstrumentationRegistry
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for CardView sample.
+ */
+@RunWith(AndroidJUnit4::class)
+class SampleTests {
+
+    private lateinit var fragment: CardViewFragment
+
+    @Rule @JvmField
+    val activityTestRule = ActivityTestRule(CardViewActivity::class.java)
+
+    @Before fun setUp() {
+        activityTestRule.activity.fragmentManager.beginTransaction()
+        fragment = activityTestRule.activity.fragmentManager
+                .findFragmentById(R.id.container) as CardViewFragment
+    }
+
+    @Test fun testPreconditions() {
+        assertNotNull(activityTestRule.activity)
+        assertNotNull(fragment)
+        assertNotNull(fragment.radiusSeekBar)
+        assertNotNull(fragment.elevationSeekBar)
+    }
+
+    @Test fun testRadiusSeekbarChangesRadiusOfCardView() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            val radius = 50.0f
+            fragment.radiusSeekBar.progress = radius.toInt()
+            assertEquals(radius, fragment.cardView.radius)
+        }
+    }
+
+    @Test fun testElevationSeekbarChangesElevationOfCardView() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            val elevation = 40.0f
+            fragment.elevationSeekBar.progress = elevation.toInt()
+            assertEquals(elevation, fragment.cardView.elevation)
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/ui/views/CardView/kotlinApp/CONTRIB.md b/ui/views/CardView/kotlinApp/CONTRIB.md
new file mode 100644
index 0000000..8ddb52d
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/CONTRIB.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual CLA]
+    (https://developers.google.com/open-source/cla/individual).
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA]
+    (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+   Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+   you are contributing. Refer to the
+   [Google Cloud Platform Samples Style Guide]
+   (https://github.com/GoogleCloudPlatform/Template/wiki/style.html) for the
+   recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/ui/views/CardView/kotlinApp/README.md b/ui/views/CardView/kotlinApp/README.md
new file mode 100644
index 0000000..df82de9
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/README.md
@@ -0,0 +1,50 @@
+
+Android CardView Sample Sample (Kotlin)
+=======================================
+
+This sample demonstrates how to use CardView introduced in the support library in
+Android 5.0.
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-CardView Sample
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2017 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/views/CardView/kotlinApp/build.gradle b/ui/views/CardView/kotlinApp/build.gradle
new file mode 100644
index 0000000..16922ca
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/build.gradle
@@ -0,0 +1,32 @@
+buildscript {
+    ext {
+        compileSdkVersion = 27
+        minSdkVersion = 21
+        targetSdkVersion = 27
+
+        espressoVersion = '3.0.1'
+        junitVersion = '4.12'
+        kotlinVersion = '1.2.10'
+        supportLibVersion = '27.0.2'
+        supportTestVersion = '1.0.1'
+    }
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/ui/views/CardView/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/ui/views/CardView/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/CardView/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/ui/views/CardView/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..a611e63
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Dec 14 19:44:05 PST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
\ No newline at end of file
diff --git a/ui/views/CardView/kotlinApp/gradlew b/ui/views/CardView/kotlinApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/ui/views/CardView/kotlinApp/gradlew.bat b/ui/views/CardView/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/views/CardView/kotlinApp/settings.gradle b/ui/views/CardView/kotlinApp/settings.gradle
new file mode 100644
index 0000000..9464a35
--- /dev/null
+++ b/ui/views/CardView/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'Application'
diff --git a/ui/views/CardView/packaging.yaml b/ui/views/CardView/packaging.yaml
deleted file mode 100644
index 1dbd957..0000000
--- a/ui/views/CardView/packaging.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-# GOOGLE SAMPLE PACKAGING DATA
-#
-# This file is used by Google as part of our samples packaging process.
-# End users may safely ignore this file. It has no relevance to other systems.
----
-status:       PUBLISHED
-technologies: [Android]
-categories:   [UI]
-languages:    [Java]
-solutions:    [Mobile]
-github:       googlesamples/android-CardView
-level:        INTERMEDIATE
-icon:         CardViewSample/src/main/res/drawable-xxhdpi/ic_launcher.png
-doc_refs:
-    - android:preview/material/ui-widgets.html
-license: apache2
diff --git a/ui/views/Clipping/ClippingBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/Clipping/ClippingBasic/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/views/Clipping/ClippingBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/Clipping/ClippingBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/EffectiveNavigation/build.gradle b/ui/views/EffectiveNavigation/build.gradle
index 2e36980..8585242 100644
--- a/ui/views/EffectiveNavigation/build.gradle
+++ b/ui/views/EffectiveNavigation/build.gradle
@@ -4,7 +4,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/ui/views/EffectiveNavigation/gradle/wrapper/gradle-wrapper.properties b/ui/views/EffectiveNavigation/gradle/wrapper/gradle-wrapper.properties
index d9028cc..fc5d442 100644
--- a/ui/views/EffectiveNavigation/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/EffectiveNavigation/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/Elevation/ElevationBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/Elevation/ElevationBasic/gradle/wrapper/gradle-wrapper.properties
index be6700b..1371e51 100644
--- a/ui/views/Elevation/ElevationBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/Elevation/ElevationBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/Elevation/ElevationDrag/gradle/wrapper/gradle-wrapper.properties b/ui/views/Elevation/ElevationDrag/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/views/Elevation/ElevationDrag/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/Elevation/ElevationDrag/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/wrapper/gradle-wrapper.properties
index a72aef0..3ba6b0f 100644
--- a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/HorizontalPaging/gradle/wrapper/gradle-wrapper.properties b/ui/views/HorizontalPaging/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/views/HorizontalPaging/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/HorizontalPaging/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/gradle/wrapper/gradle-wrapper.properties b/ui/views/NavigationDrawer/gradle/wrapper/gradle-wrapper.properties
index 98c1fee..b7d572b 100644
--- a/ui/views/NavigationDrawer/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/NavigationDrawer/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/kotlinApp/.google/packaging.yaml b/ui/views/NavigationDrawer/kotlinApp/.google/packaging.yaml
new file mode 100644
index 0000000..d85e367
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/.google/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status:       PUBLISHED
+technologies: [Android]
+categories:   [UI]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       googlesamples/android-Navigation Drawer
+level:        BEGINNER
+icon:         Navigation DrawerSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license:      apache2
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/build.gradle b/ui/views/NavigationDrawer/kotlinApp/Application/build.gradle
new file mode 100644
index 0000000..36d1ab8
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/build.gradle
@@ -0,0 +1,35 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion rootProject.ext.compileSdkVersion
+    defaultConfig {
+        applicationId "com.example.android.navigationdrawer"
+        minSdkVersion rootProject.ext.minSdkVersion
+        targetSdkVersion rootProject.ext.targetSdkVersion
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+    sourceSets {
+        main {
+            java.srcDirs "src/main/java"
+            res.srcDirs "src/main/res"
+        }
+        androidTest.setRoot('tests')
+        androidTest.java.srcDirs = ['tests/src']
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:$rootProject.ext.supportLibVersion"
+    implementation "com.android.support:cardview-v7:$rootProject.ext.supportLibVersion"
+    implementation "com.android.support:recyclerview-v7:$rootProject.supportLibVersion"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
+}
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/AndroidManifest.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5311964
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.navigationdrawer">
+
+    <application
+        android:allowBackup="false"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".NavigationDrawerActivity"
+            android:label="@string/app_name" >
+        </activity>
+    </application>
+
+</manifest>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/MainActivity.kt b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/MainActivity.kt
new file mode 100644
index 0000000..97a6524
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/MainActivity.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.example.android.navigationdrawer
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import android.widget.AdapterView
+import android.widget.BaseAdapter
+import android.widget.GridView
+import android.widget.TextView
+
+/**
+ * A simple launcher activity offering access to the individual samples in this project.
+ */
+class MainActivity : Activity(), AdapterView.OnItemClickListener {
+
+    private lateinit var samples: Array<Sample>
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+
+        // Prepare list of samples in this dashboard.
+        samples = arrayOf(Sample(R.string.navigationdraweractivity_title,
+                R.string.navigationdraweractivity_description,
+                Intent(this, NavigationDrawerActivity::class.java)))
+
+        // Prepare the GridView.
+        findViewById<GridView>(android.R.id.list).run {
+            adapter = SampleAdapter()
+            onItemClickListener = this@MainActivity
+        }
+    }
+
+    override fun onItemClick(container: AdapterView<*>, view: View, position: Int, id: Long) {
+        startActivity(samples[position].intent)
+    }
+
+    private inner class SampleAdapter : BaseAdapter() {
+
+        override fun getCount() = samples.size
+
+        override fun getItem(position: Int) = samples[position]
+
+        override fun getItemId(position: Int) = samples[position].hashCode().toLong()
+
+        override fun getView(position: Int, convertView: View?, container: ViewGroup): View {
+            return (convertView ?: layoutInflater.inflate(R.layout.sample_dashboard_item,
+                    container, false)).apply {
+                        findViewById<TextView>(android.R.id.text1)?.setText(
+                                samples[position].titleResId)
+                        findViewById<TextView>(android.R.id.text2)?.setText(
+                                samples[position].descriptionResId)
+                    }
+        }
+
+    }
+
+}
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/NavigationDrawerActivity.kt b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/NavigationDrawerActivity.kt
new file mode 100644
index 0000000..56f8d5a
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/NavigationDrawerActivity.kt
@@ -0,0 +1,194 @@
+/*
+ * 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.example.android.navigationdrawer
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.app.SearchManager
+import android.content.Intent
+import android.content.res.Configuration
+import android.os.Bundle
+import android.support.v4.view.GravityCompat
+import android.support.v4.widget.DrawerLayout
+import android.support.v7.app.ActionBarDrawerToggle
+import android.support.v7.widget.RecyclerView
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.widget.Toast
+
+/**
+ * This example illustrates a common usage of [DrawerLayout] in the Android support library.
+ *
+ * When a navigation (left) drawer is present, the host activity should detect presses of
+ * the action bar's Up affordance as a signal to open and close the navigation drawer. The
+ * ActionBarDrawerToggle facilitates this behavior.
+ * Items within the drawer should fall into one of two categories:
+ *
+ *  * **View switches**. A view switch follows the same basic policies as
+ * list or tab navigation in that a view switch does not create navigation history.
+ * This pattern should only be used at the root activity of a task, leaving some form
+ * of Up navigation active for activities further down the navigation hierarchy.
+ *
+ *  * **Selective Up**. The drawer allows the user to choose an alternate
+ * parent for Up navigation. This allows a user to jump across an app's navigation
+ * hierarchy at will. The application should treat this as it treats Up navigation from
+ * a different task, replacing the current task stack using TaskStackBuilder or similar.
+ * This is the only form of navigation drawer that should be used outside of the root
+ * activity of a task.
+ *
+ * Right side drawers should be used for actions, not navigation. This follows the pattern
+ * established by the Action Bar that navigation should be to the left and actions to the right.
+ * An action should be an operation performed on the current contents of the window,
+ * for example enabling or disabling a data overlay on top of the current content.
+ */
+class NavigationDrawerActivity : Activity(), PlanetAdapter.OnItemClickListener {
+
+    private lateinit var drawerLayout: DrawerLayout
+    private lateinit var drawerList: RecyclerView
+    private lateinit var drawerToggle: ActionBarDrawerToggle
+    private lateinit var newTitle: CharSequence
+    private lateinit var planetTitles: Array<String>
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_navigation_drawer)
+
+        val drawerTitle = title
+        newTitle = title
+        planetTitles = resources.getStringArray(R.array.planets_array)
+        drawerLayout = findViewById<DrawerLayout>(R.id.drawer_layout).apply {
+            setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START)
+        }
+
+        drawerList = findViewById<RecyclerView>(R.id.left_drawer).apply {
+            // Improve performance by indicating the list if fixed size.
+            setHasFixedSize(true)
+            // Set up the drawer's list view with items and click listener.
+            adapter = PlanetAdapter(planetTitles, this@NavigationDrawerActivity)
+        }
+
+        // Enable ActionBar app icon to behave as action to toggle nav drawer.
+        actionBar.run {
+            setDisplayHomeAsUpEnabled(true)
+            setHomeButtonEnabled(true)
+        }
+
+        // ActionBarDrawerToggle ties together the the proper interactions
+        // between the sliding drawer and the action bar app icon.
+        drawerToggle = object : ActionBarDrawerToggle(
+                this, /* Host Activity */
+                drawerLayout, /* DrawerLayout object */
+                R.string.drawer_open, /* "Open drawer" description for accessibility */
+                R.string.drawer_close  /* "Close drawer" description for accessibility */
+        ) {
+
+            override fun onDrawerClosed(drawerView: View) {
+                actionBar.title = newTitle
+                invalidateOptionsMenu() // Creates call to onPrepareOptionsMenu().
+            }
+
+            override fun onDrawerOpened(drawerView: View) {
+                actionBar.title = drawerTitle
+                invalidateOptionsMenu() // Creates call to onPrepareOptionsMenu().
+            }
+        }
+
+        // Set a custom shadow that overlays the main content when the drawer opens.
+        drawerLayout.addDrawerListener(drawerToggle)
+
+        if (savedInstanceState == null) selectItem(0)
+    }
+
+
+    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+        menuInflater.inflate(R.menu.navigation_drawer, menu)
+        return true
+    }
+
+    /**
+     * Called whenever we call [invalidateOptionsMenu].
+     * If the nav drawer is open, hide action items related to the content view.
+     */
+    override fun onPrepareOptionsMenu(menu: Menu) =
+            super.onPrepareOptionsMenu(menu.apply {
+                findItem(R.id.action_websearch).isVisible = !drawerLayout.isDrawerOpen(drawerList)
+            })
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        // The action bar home/up action should open or close the drawer.
+        // ActionBarDrawerToggle will take care of this.
+        if (drawerToggle.onOptionsItemSelected(item)) {
+            return true
+        }
+
+        // Handle action buttons
+        return when (item.itemId) {
+            R.id.action_websearch -> {
+                // Create intent to perform web search for this planet.
+                val intent = Intent(Intent.ACTION_WEB_SEARCH).apply {
+                    putExtra(SearchManager.QUERY, actionBar.title)
+                }
+                // Catch event that there's no activity to handle intent.
+                if (intent.resolveActivity(packageManager) != null) {
+                    startActivity(intent)
+                } else {
+                    Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show()
+                }
+                true
+            }
+            else -> super.onOptionsItemSelected(item)
+        }
+    }
+
+    /* The click listener for RecyclerView in the navigation drawer. */
+    override fun onClick(view: View, position: Int) {
+        selectItem(position)
+    }
+
+    override fun setTitle(title: CharSequence) {
+        newTitle = title
+        actionBar.title = title
+    }
+
+    /**
+     * If [ActionBarDrawerToggle] is used, it must be called in [onPostCreate] and
+     * [onConfigurationChanged].
+     */
+    override fun onPostCreate(savedInstanceState: Bundle?) {
+        super.onPostCreate(savedInstanceState)
+        // Sync the toggle state after has occurred.
+        drawerToggle.syncState()
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        // Pass any configuration change to the drawer toggle.
+        drawerToggle.onConfigurationChanged(newConfig)
+    }
+
+    @SuppressLint("CommitTransaction") // commit() is called
+    private fun selectItem(position: Int) {
+        fragmentManager.beginTransaction().run {
+            replace(R.id.content_frame, PlanetFragment.newInstance(position))
+            commit()
+        }
+        title = planetTitles[position]
+        drawerLayout.closeDrawer(drawerList)
+    }
+
+}
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/PlanetAdapter.kt b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/PlanetAdapter.kt
new file mode 100644
index 0000000..3ded2b1
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/PlanetAdapter.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.example.android.navigationdrawer
+
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+
+/**
+ * Adapter for the planet data used in our drawer menu.
+ */
+class PlanetAdapter(
+        private val dataset: Array<String>,
+        private val listener: OnItemClickListener
+) : RecyclerView.Adapter<PlanetAdapter.ViewHolder>() {
+
+    /**
+     * Interface for receiving click events from cells.
+     */
+    interface OnItemClickListener {
+        fun onClick(view: View, position: Int)
+    }
+
+    /**
+     * Custom [ViewHolder] for our planet views.
+     */
+    class ViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView)
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
+        ViewHolder(LayoutInflater.from(parent.context)
+                .inflate(R.layout.drawer_list_item, parent, false)
+                .findViewById(android.R.id.text1))
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        holder.apply {
+            textView.text = dataset[position]
+            textView.setOnClickListener { view -> listener.onClick(view, position) }
+        }
+    }
+
+    override fun getItemCount() = dataset.size
+}
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/PlanetFragment.kt b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/PlanetFragment.kt
new file mode 100644
index 0000000..cd1c937
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/PlanetFragment.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.example.android.navigationdrawer
+
+import android.app.Fragment
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+
+import java.util.Locale
+
+/**
+ * Fragment that appears in the "content_frame" and shows a planet.
+ */
+class PlanetFragment : Fragment() {
+
+    override fun onCreateView(
+            inflater: LayoutInflater,
+            container: ViewGroup?,
+            savedInstanceState: Bundle?
+    ): View? {
+        val planetNumber = arguments.getInt(ARG_PLANET_NUMBER)
+        val planet = resources.getStringArray(R.array.planets_array)[planetNumber]
+        val imageId = resources.getIdentifier(planet.toLowerCase(Locale.getDefault()),
+                "drawable", activity.packageName)
+        activity.title = planet
+
+        return inflater.inflate(R.layout.fragment_planet, container, false).apply {
+            findViewById<ImageView>(R.id.image).setImageResource(imageId)
+        }
+    }
+
+    companion object {
+        private val ARG_PLANET_NUMBER = "planet_number"
+
+        fun newInstance(position: Int) = PlanetFragment().apply {
+            arguments = Bundle().apply {
+                putInt(ARG_PLANET_NUMBER, position)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/Sample.kt b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/Sample.kt
new file mode 100644
index 0000000..0a13e98
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/java/com/example/android/navigationdrawer/Sample.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.example.android.navigationdrawer
+
+import android.content.Intent
+
+class Sample(var titleResId: Int, var descriptionResId: Int, var intent: Intent)
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/action_search.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/action_search.png
new file mode 100755
index 0000000..f12e005
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/action_search.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/drawer_shadow.9.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..224cc4f
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/drawer_shadow.9.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/ic_drawer.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/ic_drawer.png
new file mode 100644
index 0000000..ff7b1de
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/ic_drawer.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..b460d60
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/action_search.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/action_search.png
new file mode 100755
index 0000000..587d9e0
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/action_search.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/drawer_shadow.9.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..3797f99
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/drawer_shadow.9.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/ic_drawer.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/ic_drawer.png
new file mode 100644
index 0000000..fb681ba
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/ic_drawer.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..dee53f4
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/action_search.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/action_search.png
new file mode 100755
index 0000000..3549f84
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/action_search.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..fa3d853
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/drawer_shadow.9.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_drawer.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_drawer.png
new file mode 100644
index 0000000..b9bc3d7
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_drawer.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..d4e1215
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/earth.jpg b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/earth.jpg
new file mode 100644
index 0000000..6cabbf4
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/earth.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/jupiter.jpg b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/jupiter.jpg
new file mode 100644
index 0000000..24e8eea
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/jupiter.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/mars.jpg b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/mars.jpg
new file mode 100644
index 0000000..db253ef
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/mars.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/mercury.jpg b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/mercury.jpg
new file mode 100644
index 0000000..531790b
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/mercury.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/neptune.jpg b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/neptune.jpg
new file mode 100644
index 0000000..88467c5
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/neptune.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/saturn.jpg b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/saturn.jpg
new file mode 100644
index 0000000..8219d18
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/saturn.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/uranus.jpg b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/uranus.jpg
new file mode 100644
index 0000000..fa32e37
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/uranus.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/venus.jpg b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/venus.jpg
new file mode 100644
index 0000000..e04f078
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/drawable/venus.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/activity_main.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/activity_main.xml
new file mode 100755
index 0000000..b5d00b6
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/activity_main.xml
@@ -0,0 +1,42 @@
+<?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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView style="@style/Widget.SampleMessage"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/horizontal_page_margin"
+        android:layout_marginRight="@dimen/horizontal_page_margin"
+        android:layout_marginTop="@dimen/vertical_page_margin"
+        android:layout_marginBottom="@dimen/vertical_page_margin"
+        android:text="@string/intro_message" />
+
+    <GridView android:id="@android:id/list"
+        style="@style/Widget.SampleDashboard.Grid"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:paddingLeft="@dimen/horizontal_page_margin"
+        android:paddingRight="@dimen/horizontal_page_margin"
+        android:paddingBottom="@dimen/vertical_page_margin"
+        android:scrollbarStyle="outsideOverlay" />
+
+</LinearLayout>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/activity_navigation_drawer.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/activity_navigation_drawer.xml
new file mode 100644
index 0000000..2069035
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/activity_navigation_drawer.xml
@@ -0,0 +1,52 @@
+<?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.
+  -->
+
+<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for
+     both width and height to consume the full space available. -->
+<android.support.v4.widget.DrawerLayout
+    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/drawer_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:openDrawer="start" >
+
+    <!-- As the main content view, the view below consumes the entire
+         space available using match_parent in both dimensions. -->
+    <FrameLayout
+        android:id="@+id/content_frame"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <!-- android:layout_gravity="start" tells DrawerLayout to treat
+         this as a sliding drawer on the left side for left-to-right
+         languages and on the right side for right-to-left languages.
+         The drawer is given a fixed width in dp and extends the full height of
+         the container. A solid background is used for contrast
+         with the content view. -->
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/left_drawer"
+        android:scrollbars="vertical"
+        android:layout_width="@dimen/recycler_view_width"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"
+        android:choiceMode="singleChoice"
+        android:divider="@null"
+        app:layoutManager="LinearLayoutManager"
+        />
+</android.support.v4.widget.DrawerLayout>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/drawer_list_item.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/drawer_list_item.xml
new file mode 100644
index 0000000..bb343a7
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/drawer_list_item.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
+    android:gravity="center_vertical"
+    android:paddingLeft="@dimen/list_item_padding"
+    android:paddingRight="@dimen/list_item_padding"
+    android:textColor="@color/list_item_text_color"
+    android:background="?android:attr/activatedBackgroundIndicator"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"/>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/fragment_planet.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/fragment_planet.xml
new file mode 100644
index 0000000..dad1c8c
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/fragment_planet.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/image"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/black"
+    android:gravity="center"
+    android:padding="@dimen/fragment_imageview_padding"
+    android:contentDescription="@string/image_of_planet" />
+
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/sample_dashboard_item.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/sample_dashboard_item.xml
new file mode 100644
index 0000000..a50dec8
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/layout/sample_dashboard_item.xml
@@ -0,0 +1,50 @@
+<?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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <!-- The CardView needs to be wrapped to ensure spacing is applied correctly. -->
+    <android.support.v7.widget.CardView
+        style="@style/Widget.SampleDashboard.Card"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <LinearLayout
+            style="@style/Widget.SampleDashboard.Item"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <TextView
+                android:id="@android:id/text1"
+                style="@style/Widget.SampleDashboard.Item.Title"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+
+            <TextView
+                android:id="@android:id/text2"
+                style="@style/Widget.SampleDashboard.Item.Description"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+
+        </LinearLayout>
+
+    </android.support.v7.widget.CardView>
+
+</FrameLayout>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/menu/navigation_drawer.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/menu/navigation_drawer.xml
new file mode 100644
index 0000000..0b8073c
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/menu/navigation_drawer.xml
@@ -0,0 +1,25 @@
+<?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.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item android:id="@+id/action_websearch"
+        android:title="@string/action_websearch"
+        app:showAsAction="withText" />
+
+</menu>
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values-v20/styles.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values-v20/styles.xml
new file mode 100644
index 0000000..3ebee21
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values-v20/styles.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+
+<resources>
+    <style name="AppTheme" parent="android:Theme.Material.Light" />
+</resources>
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml
new file mode 100644
index 0000000..64366f8
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+
+<resources>
+    <style name="Theme.Base" parent="android:Theme.Material.Light" />
+</resources>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/activitycards-colors.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/activitycards-colors.xml
new file mode 100644
index 0000000..707a7a5
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/activitycards-colors.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+
+<resources>
+    <color name="teal">#009688</color>
+    <color name="black_87">#DD000000</color>
+    <color name="black_54">#89000000</color>
+</resources>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/activitycards-dimens.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/activitycards-dimens.xml
new file mode 100644
index 0000000..118ca76
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/activitycards-dimens.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+
+<resources>
+    <dimen name="card_padding">16dp</dimen>
+    <dimen name="card_margin">8dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/activitycards-strings.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/activitycards-strings.xml
new file mode 100644
index 0000000..d89af25
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/activitycards-strings.xml
@@ -0,0 +1,24 @@
+<?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.
+  -->
+
+<resources>
+    <string name="navigationdraweractivity_title">Navigation Drawer Example</string>
+    <string name="navigationdraweractivity_description">
+        This example illustrates a common usage of the DrawerLayout widget in the Android support
+        library.
+    </string>
+</resources>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/colors.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..59e9706
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+
+<resources>
+    <color name="list_item_text_color">#fff</color>
+</resources>
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/dimens.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..e2252c6
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+
+<resources>
+    <dimen name="recycler_view_width">240dp</dimen>
+    <dimen name="list_item_padding">16dp</dimen>
+    <dimen name="fragment_imageview_padding">32dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/strings.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..a196624
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/strings.xml
@@ -0,0 +1,43 @@
+<?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.
+  -->
+
+<resources>
+    <string name="app_name">Navigation Drawer</string>
+    <string name="intro_message">
+        <![CDATA[
+
+             This example illustrates a common usage of the DrawerLayout widget in the Android
+             support library.
+
+        ]]>
+    </string>
+    <string-array name="planets_array">
+        <item>Mercury</item>
+        <item>Venus</item>
+        <item>Earth</item>
+        <item>Mars</item>
+        <item>Jupiter</item>
+        <item>Saturn</item>
+        <item>Uranus</item>
+        <item>Neptune</item>
+    </string-array>
+    <string name="drawer_open">Open navigation drawer</string>
+    <string name="drawer_close">Close navigation drawer</string>
+    <string name="action_websearch">Web search</string>
+    <string name="app_not_available">Sorry, there\'s no web browser available</string>
+    <string name="image_of_planet">Image of planet</string>
+</resources>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/template-dimens.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/template-dimens.xml
new file mode 100644
index 0000000..0330809
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/template-dimens.xml
@@ -0,0 +1,33 @@
+<?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.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/template-styles.xml b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/template-styles.xml
new file mode 100644
index 0000000..ad1a282
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/Application/src/main/res/values/template-styles.xml
@@ -0,0 +1,77 @@
+<?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.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleContentContainer">
+        <item name="android:paddingTop">@dimen/vertical_page_margin</item>
+        <item name="android:paddingBottom">@dimen/vertical_page_margin</item>
+        <item name="android:paddingLeft">@dimen/horizontal_page_margin</item>
+        <item name="android:paddingRight">@dimen/horizontal_page_margin</item>
+    </style>
+
+<style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+        <item name="android:textColor">@color/black_54</item>
+    </style>
+
+    <style name="Widget.SampleDashboard.Grid" parent="Widget">
+        <item name="android:stretchMode">columnWidth</item>
+        <item name="android:columnWidth">200dp</item>
+        <item name="android:numColumns">auto_fit</item>
+        <item name="android:drawSelectorOnTop">true</item>
+        <item name="android:horizontalSpacing">0dp</item>
+        <item name="android:verticalSpacing">0dp</item>
+    </style>
+
+    <style name="Widget.SampleDashboard.Card" parent="Widget">
+        <item name="android:gravity">center</item>
+        <item name="android:layout_margin">@dimen/card_margin</item>
+        <item name="cardCornerRadius">4dp</item>
+        <item name="cardElevation">5dp</item>
+        <item name="contentPadding">@dimen/card_padding</item>
+    </style>
+
+    <style name="Widget.SampleDashboard.Item" parent="Widget">
+    </style>
+
+    <style name="Widget.SampleDashboard.Item.Title" parent="Widget">
+        <item name="android:layout_marginBottom">@dimen/margin_tiny</item>
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:textColor">@color/teal</item>
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:textSize">24sp</item>
+    </style>
+
+    <style name="Widget.SampleDashboard.Item.Description" parent="Widget">
+        <item name="android:textAppearance">?android:textAppearanceSmall</item>
+        <item name="android:fontFamily">sans-serif-light</item>
+        <item name="android:textColor">@color/black_87</item>
+    </style>
+</resources>
diff --git a/ui/views/NavigationDrawer/kotlinApp/CONTRIB.md b/ui/views/NavigationDrawer/kotlinApp/CONTRIB.md
new file mode 100644
index 0000000..14a4fcf
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/CONTRIB.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual CLA]
+    (https://developers.google.com/open-source/cla/individual).
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA]
+    (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+   Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+   you are contributing. Refer to the
+   [Android Code Style Guide]
+   (https://source.android.com/source/code-style.html) for the
+   recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/ui/views/NavigationDrawer/kotlinApp/README.md b/ui/views/NavigationDrawer/kotlinApp/README.md
new file mode 100644
index 0000000..734fa26
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/README.md
@@ -0,0 +1,50 @@
+
+Android Navigation Drawer Sample (Kotlin)
+=========================================
+
+This example illustrates a common usage of the DrawerLayout widget in the Android
+support library.
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-NavigationDrawer
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2018 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/views/NavigationDrawer/kotlinApp/build.gradle b/ui/views/NavigationDrawer/kotlinApp/build.gradle
new file mode 100644
index 0000000..3b2073b
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/build.gradle
@@ -0,0 +1,29 @@
+buildscript {
+    ext {
+        compileSdkVersion = 27
+        minSdkVersion = 21
+        targetSdkVersion = 27
+
+        kotlinVersion = '1.2.10'
+        supportLibVersion = '27.0.2'
+    }
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/ui/views/NavigationDrawer/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/NavigationDrawer/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/ui/views/NavigationDrawer/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..bd46b79
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Jan 09 12:45:11 PST 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/ui/views/NavigationDrawer/kotlinApp/gradlew b/ui/views/NavigationDrawer/kotlinApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/ui/views/NavigationDrawer/kotlinApp/gradlew.bat b/ui/views/NavigationDrawer/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/views/NavigationDrawer/kotlinApp/settings.gradle b/ui/views/NavigationDrawer/kotlinApp/settings.gradle
new file mode 100644
index 0000000..9464a35
--- /dev/null
+++ b/ui/views/NavigationDrawer/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'Application'
diff --git a/ui/views/RecyclerView/.google/packaging.yaml b/ui/views/RecyclerView/.google/packaging.yaml
new file mode 100644
index 0000000..b850c52
--- /dev/null
+++ b/ui/views/RecyclerView/.google/packaging.yaml
@@ -0,0 +1,16 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [UI]
+languages:    [Java]
+solutions:    [Mobile]
+github:       android-RecyclerView
+level:        INTERMEDIATE
+icon:         RecyclerViewSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+doc_refs:
+    - android:preview/material/ui-widgets.html
+license: apache2
diff --git a/ui/views/RecyclerView/README.md b/ui/views/RecyclerView/README.md
index 7360951..c510491 100644
--- a/ui/views/RecyclerView/README.md
+++ b/ui/views/RecyclerView/README.md
@@ -29,8 +29,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 24
-- Android Build Tools v24.0.2
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
@@ -59,7 +59,7 @@
 License
 -------
 
-Copyright 2016 The Android Open Source Project, Inc.
+Copyright 2017 The Android Open Source Project, Inc.
 
 Licensed to the Apache Software Foundation (ASF) under one or more contributor
 license agreements.  See the NOTICE file distributed with this work for
diff --git a/ui/views/RecyclerView/gradle/wrapper/gradle-wrapper.properties b/ui/views/RecyclerView/gradle/wrapper/gradle-wrapper.properties
index e1c00f6..56fe372 100644
--- a/ui/views/RecyclerView/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/RecyclerView/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/RecyclerView/kotlinApp/.gitignore b/ui/views/RecyclerView/kotlinApp/.gitignore
new file mode 100644
index 0000000..39fb081
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/ui/views/RecyclerView/kotlinApp/.google/packaging.yaml b/ui/views/RecyclerView/kotlinApp/.google/packaging.yaml
new file mode 100644
index 0000000..baab73d
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/.google/packaging.yaml
@@ -0,0 +1,20 @@
+
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status:       PUBLISHED
+technologies: [Android]
+categories:   [UI, Views]
+languages:    [Kotlin]
+solutions:    [Mobile]
+github:       android-RecyclerView
+level:        INTERMEDIATE
+icon:         screenshots/icon-web.png
+apiRefs:
+    - android:android.support.v7.widget.RecyclerView
+    - android:android.support.v7.widget.LinearLayoutManager
+    - android:android.support.v7.widget.GridLayoutManager
+    - android:android.support.v7.widget.RecyclerView.ViewHolder
+license:      apache2
diff --git a/ui/views/RecyclerView/kotlinApp/README.md b/ui/views/RecyclerView/kotlinApp/README.md
new file mode 100644
index 0000000..ebba27d
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/README.md
@@ -0,0 +1,78 @@
+
+Android RecyclerView Sample (Kotlin)
+====================================
+
+Sample demonstrating the use of RecyclerView to layout elements with a
+LinearLayoutManager and with a GridLayoutManager. It also demonstrates
+how to handle touch events on elements.
+
+
+Introduction
+------------
+
+Sample demonstrating the use of [RecyclerView][1] to layout elements with a
+[LinearLayoutManager][2] or with a [GridLayoutManager][3].
+
+[RecyclerView][1] can display large datasets that can be scrolled
+efficiently by recycling a limited number of views. Click listeners can be
+defined when [ViewHolder][4] views are instantiated. [RecyclerView][1] is
+available in the v7 Support Library, thus compatible with API level 7 and above.
+
+Tap "Show Log" menu item to display log of elements as they are laid out and
+tapped. Use radio buttons to toggle between [LinearLayoutManager][2] and
+[GridLayoutManager][3].
+
+[1]: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
+[2]: https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager.html
+[3]: https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.html
+[4]: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Gradle Plugin 3.0
+- Android Support Repository
+
+Screenshots
+-------------
+
+<img src="screenshots/1-linear.png" height="400" alt="Screenshot"/> <img src="screenshots/2-grid.png" height="400" alt="Screenshot"/>
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-RecyclerView
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2017 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/views/RecyclerView/kotlinApp/app/.gitignore b/ui/views/RecyclerView/kotlinApp/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/ui/views/RecyclerView/kotlinApp/app/build.gradle b/ui/views/RecyclerView/kotlinApp/app/build.gradle
new file mode 100644
index 0000000..fd409cf
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/build.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion 27
+    defaultConfig {
+        applicationId "com.example.android.recyclerview"
+        minSdkVersion 14
+        targetSdkVersion 27
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+
+    lintOptions {
+        abortOnError false
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:27.0.2"
+    implementation 'com.android.support:recyclerview-v7:27.0.2'
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/proguard-rules.pro b/ui/views/RecyclerView/kotlinApp/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/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/ui/views/RecyclerView/kotlinApp/app/src/main/AndroidManifest.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d21f57c
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.recyclerview">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/activities/SampleActivityBase.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/activities/SampleActivityBase.kt
new file mode 100644
index 0000000..0d7003e
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/activities/SampleActivityBase.kt
@@ -0,0 +1,52 @@
+/*
+* Copyright 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 com.example.android.common.activities
+
+import android.os.Bundle
+import android.support.v4.app.FragmentActivity
+
+import com.example.android.common.logger.Log
+import com.example.android.common.logger.LogWrapper
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+open class SampleActivityBase : FragmentActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+    }
+
+    override fun onStart() {
+        super.onStart()
+        initializeLogging()
+    }
+
+    /** Set up targets to receive log data  */
+    open fun initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        val logWrapper = LogWrapper()
+        Log.logNode = logWrapper
+
+        Log.i(TAG, "Ready")
+    }
+
+    companion object {
+        val TAG = "SampleActivityBase"
+    }
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/Log.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/Log.kt
new file mode 100644
index 0000000..7cbf5eb
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/Log.kt
@@ -0,0 +1,133 @@
+/*
+ * 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 com.example.android.common.logger
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ *
+ * When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for [android.util.Log].
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.
+ */
+object Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    val NONE = -1
+    val VERBOSE = android.util.Log.VERBOSE
+    val DEBUG = android.util.Log.DEBUG
+    val INFO = android.util.Log.INFO
+    val WARN = android.util.Log.WARN
+    val ERROR = android.util.Log.ERROR
+    val ASSERT = android.util.Log.ASSERT
+
+    // Stores the beginning of the LogNode topology.
+    var logNode: LogNode? = null
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    fun println(priority: Int, tag: String, msg: String?, tr: Throwable? = null) {
+
+        logNode?.println(priority, tag, msg, tr)
+
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    fun v(tag: String, msg: String? = null, tr: Throwable? = null) {
+        println(VERBOSE, tag, msg, tr)
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    fun d(tag: String, msg: String? = null, tr: Throwable? = null) {
+        println(DEBUG, tag, msg, tr)
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    fun i(tag: String, msg: String, tr: Throwable? = null) {
+        println(INFO, tag, msg, tr)
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    fun w(tag: String, msg: String? = null, tr: Throwable? = null) {
+        println(WARN, tag, msg, tr)
+    }
+
+
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    fun e(tag: String, msg: String, tr: Throwable? = null) {
+        println(ERROR, tag, msg, tr)
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    fun wtf(tag: String, msg: String? = null, tr: Throwable? = null) {
+        println(ASSERT, tag, msg, tr)
+    }
+
+
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogFragment.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogFragment.kt
new file mode 100644
index 0000000..49555bf
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogFragment.kt
@@ -0,0 +1,91 @@
+/*
+* Copyright 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 com.example.android.common.logger
+
+import android.content.Context
+import android.graphics.Typeface
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.support.v4.widget.TextViewCompat
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ScrollView
+
+/**
+ * Simple fragment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+class LogFragment : Fragment() {
+
+    lateinit var logView: LogView
+        private set
+
+    private lateinit var scrollView: ScrollView
+
+    private fun inflateViews(): View {
+        scrollView = ScrollView(activity)
+        val scrollParams = ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT)
+        scrollView.layoutParams = scrollParams
+
+        logView = LogView(activity as Context)
+        val logParams = ViewGroup.LayoutParams(scrollParams)
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
+
+        with(logView) {
+            layoutParams = logParams
+            isClickable = true
+            isFocusable = true
+            typeface = Typeface.MONOSPACE
+        }
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        val paddingDips = 16
+        val scale = resources.displayMetrics.density.toDouble()
+        val paddingPixels = (paddingDips * scale + .5).toInt()
+        logView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels)
+        logView.compoundDrawablePadding = paddingPixels
+
+        logView.gravity = Gravity.BOTTOM
+        TextViewCompat.setTextAppearance(logView, android.R.style.TextAppearance_Holo_Medium)
+
+        scrollView.addView(logView)
+        return scrollView
+    }
+
+     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+                              savedInstanceState: Bundle?): View? {
+
+        val result = inflateViews()
+
+        logView.addTextChangedListener(object : TextWatcher {
+            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+
+            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
+
+            override fun afterTextChanged(s: Editable) {
+                scrollView.fullScroll(ScrollView.FOCUS_DOWN)
+            }
+        })
+        return result
+    }
+}
\ No newline at end of file
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogNode.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogNode.kt
new file mode 100644
index 0000000..6259f02
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogNode.kt
@@ -0,0 +1,39 @@
+/*
+ * 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 com.example.android.common.logger
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    fun println(priority: Int, tag: String?, msg: String?, tr: Throwable?)
+
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogView.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogView.kt
new file mode 100644
index 0000000..ecb5ed5
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogView.kt
@@ -0,0 +1,105 @@
+/*
+ * 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 com.example.android.common.logger
+
+import android.app.Activity
+import android.content.Context
+import android.util.*
+import android.widget.TextView
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+ */
+class LogView : TextView, LogNode {
+
+    // The next LogNode in the chain.
+    private var next: LogNode? = null
+
+    @JvmOverloads
+    constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
+            super(context, attrs, defStyle)
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    override fun println(priority: Int, tag: String?, msg: String?, tr: Throwable?) {
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        val priorityStr = when (priority) {
+            android.util.Log.VERBOSE -> "VERBOSE"
+            android.util.Log.DEBUG -> "DEBUG"
+            android.util.Log.INFO -> "INFO"
+            android.util.Log.WARN -> "WARN"
+            android.util.Log.ERROR -> "ERROR"
+            android.util.Log.ASSERT -> "ASSERT"
+            else -> null
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        val exceptionStr = tr?.let{ android.util.Log.getStackTraceString(it) }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        val outputBuilder = StringBuilder()
+
+        val delimiter = "\t"
+        appendIfNotNull(outputBuilder, priorityStr, delimiter)
+        appendIfNotNull(outputBuilder, tag, delimiter)
+        appendIfNotNull(outputBuilder, msg, delimiter)
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter)
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        (context as Activity).runOnUiThread( {
+            // Display the text we just generated within the LogView.
+            appendToLog(outputBuilder.toString())
+        })
+
+
+        next?.println(priority, tag, msg, tr)
+
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     * for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private fun appendIfNotNull(source: StringBuilder, addStr: String?, delimiter: String): StringBuilder {
+
+        if (addStr != null && !addStr.isEmpty()) {
+            return source.append(addStr).append(delimiter)
+        }
+
+        return source
+
+    }
+
+    /** Outputs the string as a new line of log data in the LogView.  */
+    private fun appendToLog(s: String) {
+        append("\n" + s)
+    }
+
+
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogWrapper.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogWrapper.kt
new file mode 100644
index 0000000..381b57a
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/LogWrapper.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.common.logger
+
+import android.util.Log
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+class LogWrapper : LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    var next: LogNode? = null
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     * to extract and print useful information.
+     */
+    override fun println(priority: Int, tag: String?, msg: String?, tr: Throwable?) {
+        var msg = msg
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        var useMsg: String? = msg
+        if (useMsg == null) {
+            useMsg = ""
+        }
+
+        // If an exception was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n$Log.getStackTraceString(tr)"
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg)
+
+        // If this isn't the last node in the chain, move things along.
+        next?.println(priority, tag, msg, tr)
+
+    }
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.kt
new file mode 100644
index 0000000..5ec926f
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.kt
@@ -0,0 +1,34 @@
+/*
+ * 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 com.example.android.common.logger
+
+/**
+ * Simple [LogNode] filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+class MessageOnlyLogFilter : LogNode {
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    var next: LogNode? = null
+
+    override fun println(priority: Int, tag: String?, msg: String?, tr: Throwable?) {
+        next?.println(Log.NONE, null, msg, null)
+    }
+
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/recyclerview/CustomAdapter.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/recyclerview/CustomAdapter.kt
new file mode 100644
index 0000000..866e4eb
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/recyclerview/CustomAdapter.kt
@@ -0,0 +1,74 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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.recyclerview
+
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+
+import com.example.android.common.logger.Log
+
+/**
+ * Provide views to RecyclerView with data from dataSet.
+ *
+ * Initialize the dataset of the Adapter.
+ *
+ * @param dataSet String[] containing the data to populate views to be used by RecyclerView.
+ */
+class CustomAdapter(private val dataSet: Array<String>) :
+        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
+
+    /**
+     * Provide a reference to the type of views that you are using (custom ViewHolder)
+     */
+    class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
+        val textView: TextView
+
+        init {
+            // Define click listener for the ViewHolder's View.
+            v.setOnClickListener { Log.d(TAG, "Element $adapterPosition clicked.") }
+            textView = v.findViewById(R.id.textView)
+        }
+    }
+
+    // Create new views (invoked by the layout manager)
+    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
+        // Create a new view.
+        val v = LayoutInflater.from(viewGroup.context)
+                .inflate(R.layout.text_row_item, viewGroup, false)
+
+        return ViewHolder(v)
+    }
+
+    // Replace the contents of a view (invoked by the layout manager)
+    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
+        Log.d(TAG, "Element $position set.")
+
+        // Get element from your dataset at this position and replace the contents of the view
+        // with that element
+        viewHolder.textView.text = dataSet[position]
+    }
+
+    // Return the size of your dataset (invoked by the layout manager)
+    override fun getItemCount() = dataSet.size
+
+    companion object {
+        private val TAG = "CustomAdapter"
+    }
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/recyclerview/MainActivity.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/recyclerview/MainActivity.kt
new file mode 100644
index 0000000..c1097fa
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/recyclerview/MainActivity.kt
@@ -0,0 +1,107 @@
+/*
+* Copyright 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 com.example.android.recyclerview
+
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
+import android.widget.ViewAnimator
+
+import com.example.android.common.activities.SampleActivityBase
+import com.example.android.common.logger.Log
+import com.example.android.common.logger.LogFragment
+import com.example.android.common.logger.LogWrapper
+import com.example.android.common.logger.MessageOnlyLogFilter
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * [android.support.v4.app.Fragment] which can display a view.
+ *
+ *
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+class MainActivity : SampleActivityBase() {
+
+    // Whether the Log Fragment is currently shown
+    private var logShown = false
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+
+        if (savedInstanceState == null) {
+            supportFragmentManager.beginTransaction().run {
+                replace(R.id.sample_content_fragment, RecyclerViewFragment())
+                commit()
+            }
+        }
+    }
+
+    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+        menuInflater.inflate(R.menu.main, menu)
+        return true
+    }
+
+    override fun onPrepareOptionsMenu(menu: Menu): Boolean {
+        menu.findItem(R.id.menu_toggle_log).run {
+            isVisible = findViewById<ViewAnimator>(R.id.sample_output) is ViewAnimator
+            setTitle(if (logShown) R.string.sample_hide_log else R.string.sample_show_log)
+        }
+
+        return super.onPrepareOptionsMenu(menu)
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
+        R.id.menu_toggle_log -> {
+            logShown = !logShown
+            val output = findViewById<ViewAnimator>(R.id.sample_output) as ViewAnimator
+
+            output.displayedChild = if (logShown) 1 else 0
+
+            invalidateOptionsMenu()
+            true
+        }
+        else -> super.onOptionsItemSelected(item)
+    }
+
+
+
+    /** Create a chain of targets that will receive log data  */
+    override fun initializeLogging() {
+        // Wraps Android's native log framework.
+        val logWrapper = LogWrapper()
+
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.logNode = logWrapper
+
+        // Filter strips out everything except the message text.
+        val msgFilter = MessageOnlyLogFilter()
+        logWrapper.next = msgFilter
+
+        // On screen logging via a fragment with a TextView.
+        val logFragment = supportFragmentManager.findFragmentById(R.id.log_fragment) as LogFragment
+        msgFilter.next = logFragment.logView
+
+        Log.i(TAG, "Ready")
+    }
+
+    companion object {
+        val TAG = "MainActivity"
+    }
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.kt b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.kt
new file mode 100644
index 0000000..9ad0ede
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.kt
@@ -0,0 +1,139 @@
+/*
+* 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 com.example.android.recyclerview
+
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.support.v7.widget.GridLayoutManager
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.RadioButton
+
+/**
+ * Demonstrates the use of [RecyclerView] with a [LinearLayoutManager] and a
+ * [GridLayoutManager].
+ */
+class RecyclerViewFragment : Fragment() {
+
+    private lateinit var currentLayoutManagerType: LayoutManagerType
+    private lateinit var recyclerView: RecyclerView
+    private lateinit var layoutManager: RecyclerView.LayoutManager
+    private lateinit var dataset: Array<String>
+
+    enum class LayoutManagerType { GRID_LAYOUT_MANAGER, LINEAR_LAYOUT_MANAGER }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        // Initialize dataset, this data would usually come from a local content provider or
+        // remote server.
+        initDataset()
+    }
+
+    override fun onCreateView(inflater: LayoutInflater,
+                              container: ViewGroup?,
+                              savedInstanceState: Bundle?): View? {
+        val rootView = inflater.inflate(R.layout.recycler_view_frag,
+                container, false).apply { tag = TAG}
+
+        recyclerView = rootView.findViewById(R.id.recyclerView)
+
+        // LinearLayoutManager is used here, this will layout the elements in a similar fashion
+        // to the way ListView would layout elements. The RecyclerView.LayoutManager defines how
+        // elements are laid out.
+        layoutManager = LinearLayoutManager(activity)
+
+        currentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER
+
+        if (savedInstanceState != null) {
+            // Restore saved layout manager type.
+            currentLayoutManagerType = savedInstanceState
+                    .getSerializable(KEY_LAYOUT_MANAGER) as LayoutManagerType
+        }
+        setRecyclerViewLayoutManager(currentLayoutManagerType)
+
+        // Set CustomAdapter as the adapter for RecyclerView.
+        recyclerView.adapter = CustomAdapter(dataset)
+
+        rootView.findViewById<RadioButton>(R.id.linear_layout_rb).setOnClickListener{
+            setRecyclerViewLayoutManager(LayoutManagerType.LINEAR_LAYOUT_MANAGER)
+        }
+
+        rootView.findViewById<RadioButton>(R.id.grid_layout_rb).setOnClickListener{
+            setRecyclerViewLayoutManager(LayoutManagerType.GRID_LAYOUT_MANAGER)
+        }
+
+        return rootView
+    }
+
+    /**
+     * Set RecyclerView's LayoutManager to the one given.
+     *
+     * @param layoutManagerType Type of layout manager to switch to.
+     */
+    private fun setRecyclerViewLayoutManager(layoutManagerType: LayoutManagerType) {
+        var scrollPosition = 0
+
+        // If a layout manager has already been set, get current scroll position.
+        if (recyclerView.layoutManager != null) {
+            scrollPosition = (recyclerView.layoutManager as LinearLayoutManager)
+                    .findFirstCompletelyVisibleItemPosition()
+        }
+
+        when (layoutManagerType) {
+            RecyclerViewFragment.LayoutManagerType.GRID_LAYOUT_MANAGER -> {
+                layoutManager = GridLayoutManager(activity, SPAN_COUNT)
+                currentLayoutManagerType = LayoutManagerType.GRID_LAYOUT_MANAGER
+            }
+            RecyclerViewFragment.LayoutManagerType.LINEAR_LAYOUT_MANAGER -> {
+                layoutManager = LinearLayoutManager(activity)
+                currentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER
+            }
+        }
+
+        with(recyclerView) {
+            layoutManager = this@RecyclerViewFragment.layoutManager
+            scrollToPosition(scrollPosition)
+        }
+
+    }
+
+    override fun onSaveInstanceState(savedInstanceState: Bundle) {
+
+        // Save currently selected layout manager.
+        savedInstanceState.putSerializable(KEY_LAYOUT_MANAGER, currentLayoutManagerType)
+        super.onSaveInstanceState(savedInstanceState)
+    }
+
+    /**
+     * Generates Strings for RecyclerView's adapter. This data would usually come
+     * from a local content provider or remote server.
+     */
+    private fun initDataset() {
+        dataset = Array(DATASET_COUNT, {i -> "This is element # $i"})
+    }
+
+    companion object {
+        private val TAG = "RecyclerViewFragment"
+        private val KEY_LAYOUT_MANAGER = "layoutManager"
+        private val SPAN_COUNT = 2
+        private val DATASET_COUNT = 60
+    }
+}
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.png b/ui/views/RecyclerView/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/drawable-xxhdpi/tile.9.png b/ui/views/RecyclerView/kotlinApp/app/src/main/res/drawable-xxhdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/drawable-xxhdpi/tile.9.png
Binary files differ
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout-w720dp/activity_main.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <LinearLayout
+          android:id="@+id/sample_output"
+          android:layout_width="0px"
+          android:layout_height="match_parent"
+          android:layout_weight="1"
+          android:orientation="vertical">
+
+        <FrameLayout
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/margin_medium"
+                  android:paddingRight="@dimen/margin_medium"
+                  android:paddingTop="@dimen/margin_large"
+                  android:paddingBottom="@dimen/margin_large"
+                  android:text="@string/intro_message" />
+        </FrameLayout>
+
+        <View
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:background="@android:color/darker_gray" />
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="0px"
+              android:layout_weight="1" />
+
+    </LinearLayout>
+
+    <View
+          android:layout_width="1dp"
+          android:layout_height="match_parent"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="0px"
+          android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout/activity_main.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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"
+      android:id="@+id/sample_main_layout">
+
+    <ViewAnimator
+          android:id="@+id/sample_output"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1">
+
+        <ScrollView
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/horizontal_page_margin"
+                  android:paddingRight="@dimen/horizontal_page_margin"
+                  android:paddingTop="@dimen/vertical_page_margin"
+                  android:paddingBottom="@dimen/vertical_page_margin"
+                  android:text="@string/intro_message" />
+        </ScrollView>
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+    </ViewAnimator>
+
+    <View
+          android:layout_width="match_parent"
+          android:layout_height="1dp"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="match_parent"
+          android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout/recycler_view_frag.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout/recycler_view_frag.xml
new file mode 100644
index 0000000..dda99ce
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout/recycler_view_frag.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">
+    <RadioGroup
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_horizontal"
+        android:orientation="horizontal"
+        android:checkedButton="@+id/linear_layout_rb">
+        <RadioButton android:id="@+id/linear_layout_rb"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/linear_layout_manager"/>
+        <RadioButton android:id="@+id/grid_layout_rb"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/grid_layout_manager"/>
+    </RadioGroup>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/recyclerView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout/text_row_item.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout/text_row_item.xml
new file mode 100644
index 0000000..9b94684
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/layout/text_row_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/list_item_height"
+    android:layout_marginLeft="@dimen/margin_medium"
+    android:layout_marginRight="@dimen/margin_medium"
+    android:gravity="center_vertical">
+
+    <TextView
+        android:id="@+id/textView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/element_text"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/menu/main.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/menu/main.xml
new file mode 100644
index 0000000..29c52f8
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/menu/main.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:tools="http://schemas.android.com/tools"
+      tools:ignore="AppCompatResource">
+    <item android:id="@+id/menu_toggle_log"
+          android:showAsAction="always"
+          android:title="@string/sample_show_log" />
+</menu>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png b/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..bcb72b1
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png b/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..37e5bce
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..1c4a85a
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b26545c
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-v11/template-styles.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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>
+
+    <!-- Activity themes -->
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-v21/base-colors.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-v21/base-colors.xml
new file mode 100644
index 0000000..58f08a3
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-v21/base-colors.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">#00BCD4</color>
+        <color name="colorPrimaryDark">#00838F</color>
+
+</resources>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml
new file mode 100644
index 0000000..0995e4d
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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>
+
+    <!-- Activity themes -->
+    <style name="Theme.Base" parent="android:Theme.Material.Light">
+            <item name="android:colorPrimary">@color/colorPrimary</item>
+            <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
+    </style>
+
+</resources>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/base-strings.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/base-strings.xml
new file mode 100644
index 0000000..3ccf660
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/base-strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">RecyclerView</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+                Demonstration of using RecyclerView with a LinearLayoutManager and GridLayoutManager
+                to create a vertical list. Tap \"SHOW LOG\" to view elements as they are bound to
+                their ViewHolder. The log also displays elements that you tap.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/dimens.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..5af7e9e
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="list_item_height">72dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/fragmentview_strings.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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="sample_show_log">Show Log</string>
+    <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/strings.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..642e022
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="element_text">Element</string>
+    <string name="grid_layout_manager">Grid Layout Manager</string>
+    <string name="linear_layout_manager">Linear Layout Manager</string>
+</resources>
\ No newline at end of file
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/template-dimens.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/template-styles.xml b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/app/src/main/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/ui/views/RecyclerView/kotlinApp/build.gradle b/ui/views/RecyclerView/kotlinApp/build.gradle
new file mode 100644
index 0000000..c2ff357
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    ext.kotlin_version = '1.1.60'
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/ui/views/RecyclerView/kotlinApp/gradle.properties b/ui/views/RecyclerView/kotlinApp/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/ui/views/RecyclerView/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/ui/views/RecyclerView/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/RecyclerView/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/ui/views/RecyclerView/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..cab792c
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Nov 08 08:41:54 PST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/ui/views/RecyclerView/kotlinApp/gradlew b/ui/views/RecyclerView/kotlinApp/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/ui/views/RecyclerView/kotlinApp/gradlew.bat b/ui/views/RecyclerView/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windowz variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+if "%@eval[2+2]" == "4" goto 4NT_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+goto execute

+

+:4NT_args

+@rem Get arguments from the 4NT Shell from JP Software

+set CMD_LINE_ARGS=%$

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/ui/views/RecyclerView/kotlinApp/settings.gradle b/ui/views/RecyclerView/kotlinApp/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/ui/views/RecyclerView/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/ui/views/RecyclerView/packaging.yaml b/ui/views/RecyclerView/packaging.yaml
deleted file mode 100644
index 8554a96..0000000
--- a/ui/views/RecyclerView/packaging.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-# GOOGLE SAMPLE PACKAGING DATA
-#
-# This file is used by Google as part of our samples packaging process.
-# End users may safely ignore this file. It has no relevance to other systems.
----
-status:       PUBLISHED
-technologies: [Android]
-categories:   [UI]
-languages:    [Java]
-solutions:    [Mobile]
-github:       googlesamples/android-RecyclerView
-level:        INTERMEDIATE
-icon:         RecyclerViewSample/src/main/res/drawable-xxhdpi/ic_launcher.png
-doc_refs:
-    - android:preview/material/ui-widgets.html
-license: apache2
diff --git a/ui/views/RevealEffect/RevealEffectBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/RevealEffect/RevealEffectBasic/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/views/RevealEffect/RevealEffectBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/RevealEffect/RevealEffectBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/SlidingTabs/SlidingTabsBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/SlidingTabs/SlidingTabsBasic/gradle/wrapper/gradle-wrapper.properties
index eab6503..f8e553a 100644
--- a/ui/views/SlidingTabs/SlidingTabsBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/SlidingTabs/SlidingTabsBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/ui/views/SlidingTabs/SlidingTabsColors/gradle/wrapper/gradle-wrapper.properties b/ui/views/SlidingTabs/SlidingTabsColors/gradle/wrapper/gradle-wrapper.properties
index 16f1466..28a52c6 100644
--- a/ui/views/SlidingTabs/SlidingTabsColors/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/SlidingTabs/SlidingTabsColors/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/gradle/wrapper/gradle-wrapper.properties
index f56beca..7a0d3e9 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/gradle/wrapper/gradle-wrapper.properties b/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/gradle/wrapper/gradle-wrapper.properties b/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/views/TextSwitcher/gradle/wrapper/gradle-wrapper.properties b/ui/views/TextSwitcher/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/views/TextSwitcher/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/TextSwitcher/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/window/AdvancedImmersiveMode/Application/build.gradle b/ui/window/AdvancedImmersiveMode/Application/build.gradle
index 08444ff..0c98085 100644
--- a/ui/window/AdvancedImmersiveMode/Application/build.gradle
+++ b/ui/window/AdvancedImmersiveMode/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/ui/window/AdvancedImmersiveMode/gradle/wrapper/gradle-wrapper.properties b/ui/window/AdvancedImmersiveMode/gradle/wrapper/gradle-wrapper.properties
index 2d6fb97..064a15c 100644
--- a/ui/window/AdvancedImmersiveMode/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/window/AdvancedImmersiveMode/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/window/BasicImmersiveMode/gradle/wrapper/gradle-wrapper.properties b/ui/window/BasicImmersiveMode/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/window/BasicImmersiveMode/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/window/BasicImmersiveMode/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/window/DragAndDropAcrossApps/DragSource/build.gradle b/ui/window/DragAndDropAcrossApps/DragSource/build.gradle
index c1f1704..81b100f 100644
--- a/ui/window/DragAndDropAcrossApps/DragSource/build.gradle
+++ b/ui/window/DragAndDropAcrossApps/DragSource/build.gradle
@@ -19,7 +19,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/ui/window/DragAndDropAcrossApps/DropTarget/build.gradle b/ui/window/DragAndDropAcrossApps/DropTarget/build.gradle
index 228da1c..7dc387a 100644
--- a/ui/window/DragAndDropAcrossApps/DropTarget/build.gradle
+++ b/ui/window/DragAndDropAcrossApps/DropTarget/build.gradle
@@ -20,7 +20,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/ui/window/DragAndDropAcrossApps/gradle/wrapper/gradle-wrapper.properties b/ui/window/DragAndDropAcrossApps/gradle/wrapper/gradle-wrapper.properties
index 8264e3e..6ecb12e 100644
--- a/ui/window/DragAndDropAcrossApps/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/window/DragAndDropAcrossApps/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/window/ImmersiveMode/gradle/wrapper/gradle-wrapper.properties b/ui/window/ImmersiveMode/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/ui/window/ImmersiveMode/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/window/ImmersiveMode/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/window/MultiWindowPlayground/Application/build.gradle b/ui/window/MultiWindowPlayground/Application/build.gradle
index 3f92676..f197d17 100644
--- a/ui/window/MultiWindowPlayground/Application/build.gradle
+++ b/ui/window/MultiWindowPlayground/Application/build.gradle
@@ -20,7 +20,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/ui/window/MultiWindowPlayground/README.md b/ui/window/MultiWindowPlayground/README.md
index dbe200a..b58b285 100644
--- a/ui/window/MultiWindowPlayground/README.md
+++ b/ui/window/MultiWindowPlayground/README.md
@@ -49,13 +49,13 @@
 --------------
 
 - Android SDK 24
-- Android Build Tools v24.0.2
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
 -------------
 
-<img src="screenshots/main.png" height="400" alt="Screenshot"/> 
+<img src="screenshots/main.png" height="400" alt="Screenshot"/>
 
 Getting Started
 ---------------
@@ -78,7 +78,7 @@
 License
 -------
 
-Copyright 2016 The Android Open Source Project, Inc.
+Copyright 2017 The Android Open Source Project, Inc.
 
 Licensed to the Apache Software Foundation (ASF) under one or more contributor
 license agreements.  See the NOTICE file distributed with this work for
diff --git a/ui/window/MultiWindowPlayground/gradle/wrapper/gradle-wrapper.properties b/ui/window/MultiWindowPlayground/gradle/wrapper/gradle-wrapper.properties
index d9028cc..fc5d442 100644
--- a/ui/window/MultiWindowPlayground/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/window/MultiWindowPlayground/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/build.gradle b/ui/window/MultiWindowPlayground/kotlinApp/Application/build.gradle
new file mode 100644
index 0000000..c5b64a9
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion 27
+    defaultConfig {
+        applicationId "com.android.multiwindowplayground"
+        minSdkVersion 24
+        targetSdkVersion 27
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    implementation "com.android.support:appcompat-v7:27.0.2"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/AndroidManifest.xml b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..10a8174
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright (C) 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest package="com.android.multiwindowplayground"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <application
+        android:allowBackup="false"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/MultiWindowSampleTheme">
+        <!-- The launcher Activity that is started when the application is first started.
+         Note that we are setting the task affinity to "" to ensure each activity is launched
+         into a separate task stack. -->
+        <activity
+            android:name="com.android.multiwindowplayground.MainActivity"
+            android:taskAffinity="">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- This Activity cannot be resized and is always displayed full screen. -->
+        <activity
+            android:name="com.android.multiwindowplayground.activities.UnresizableActivity"
+            android:resizeableActivity="false"
+            android:taskAffinity="" />
+
+        <!-- This Activity has a default size (750x500dp) with a minimum size
+        (500dp at its shortest side). It is launched in the top/end (top/right) corner by default.
+         These attributes are defined in the 'layout' tag within an Activity definition. -->
+        <activity
+            android:name="com.android.multiwindowplayground.activities.MinimumSizeActivity"
+            android:launchMode="singleInstance"
+            android:taskAffinity="">
+            <layout
+                android:defaultHeight="500dp"
+                android:defaultWidth="750dp"
+                android:gravity="top|end"
+                android:minWidth="500dp"
+                android:minHeight="500dp" />
+        </activity>
+
+        <!-- In split-screen mode, this Activity is launched adjacent to another Activity. This is
+          controlled via a flag set in the intent that launches this Activity. -->
+        <activity
+            android:name="com.android.multiwindowplayground.activities.AdjacentActivity"
+            android:taskAffinity="" />
+
+        <!-- This Activity is launched within an area defined in its launch intent. -->
+        <activity
+            android:name="com.android.multiwindowplayground.activities.LaunchBoundsActivity"
+            android:taskAffinity="" />
+
+        <!-- This activity handles all configuration changes itself.
+        Callbacks for configuration changes are received in 'onConfigurationChanged'. -->
+        <activity
+            android:name="com.android.multiwindowplayground.activities.CustomConfigurationChangeActivity"
+            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+            android:launchMode="singleInstance"
+            android:taskAffinity="" />
+
+        <!-- This Activity is launched in a new task without any special flags or settings. -->
+        <activity
+            android:name="com.android.multiwindowplayground.activities.BasicActivity"
+            android:launchMode="singleInstance"
+            android:taskAffinity="" />
+
+    </application>
+
+</manifest>
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/MainActivity.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/MainActivity.kt
new file mode 100644
index 0000000..0c371a2
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/MainActivity.kt
@@ -0,0 +1,118 @@
+/*
+ * 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 com.android.multiwindowplayground
+
+import android.app.ActivityOptions
+import android.content.Intent
+import android.graphics.Rect
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import com.android.multiwindowplayground.activities.AdjacentActivity
+import com.android.multiwindowplayground.activities.BasicActivity
+import com.android.multiwindowplayground.activities.CustomConfigurationChangeActivity
+import com.android.multiwindowplayground.activities.LOG_TAG
+import com.android.multiwindowplayground.activities.LaunchBoundsActivity
+import com.android.multiwindowplayground.activities.LoggingActivity
+import com.android.multiwindowplayground.activities.MinimumSizeActivity
+import com.android.multiwindowplayground.activities.UnresizableActivity
+
+class MainActivity : LoggingActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+
+        // Display an additional message if the app is not in multiwindow mode.
+        findViewById<View>(R.id.warning_multiwindow_disabled).visibility =
+                if (!isInMultiWindowMode) View.VISIBLE else View.GONE
+    }
+
+    @Suppress("UNUSED_PARAMETER")
+    fun onStartUnresizableClick(view: View) {
+        Log.d(LOG_TAG, "** starting UnresizableActivity")
+
+        /*
+         * This activity is marked as 'unresizable' in the AndroidManifest. We need to specify the
+         * FLAG_ACTIVITY_NEW_TASK flag here to launch it into a new task stack, otherwise the
+         * properties from the root activity would have been inherited (which was here marked as
+         * resizable by default).
+        */
+        val intent = Intent(this, UnresizableActivity::class.java).apply {
+            flags = Intent.FLAG_ACTIVITY_NEW_TASK
+        }
+        startActivity(intent)
+    }
+
+    @Suppress("UNUSED_PARAMETER")
+    fun onStartMinimumSizeActivity(view: View) {
+        Log.d(LOG_TAG, "** starting MinimumSizeActivity")
+        startActivity(Intent(this, MinimumSizeActivity::class.java))
+    }
+
+    @Suppress("UNUSED_PARAMETER")
+    fun onStartAdjacentActivity(view: View) {
+        Log.d(LOG_TAG, "** starting AdjacentActivity")
+
+        /*
+         * Start this activity adjacent to the focused activity (ie. this activity) if possible.
+         * Note that this flag is just a hint to the system and may be ignored. For example,
+         * if the activity is launched within the same task, it will be launched on top of the
+         * previous activity that started the Intent. That's why the Intent.FLAG_ACTIVITY_NEW_TASK
+         * flag is specified here in the intent - this will start the activity in a new task.
+         */
+        val intent = Intent(this, AdjacentActivity::class.java).apply {
+            addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT or Intent.FLAG_ACTIVITY_NEW_TASK)
+        }
+        startActivity(intent)
+    }
+
+    @Suppress("UNUSED_PARAMETER")
+    fun onStartLaunchBoundsActivity(view: View) {
+        Log.d(LOG_TAG, "** starting LaunchBoundsActivity")
+
+        // Define the bounds in which the Activity will be launched into.
+        val bounds = Rect(500, 300, 100, 0)
+
+        // Set the bounds as an activity option.
+        val options = ActivityOptions.makeBasic().apply {
+            launchBounds = bounds
+        }
+
+        // Start the LaunchBoundsActivity with the specified options
+        val intent = Intent(this, LaunchBoundsActivity::class.java)
+        startActivity(intent, options.toBundle())
+    }
+
+    @Suppress("UNUSED_PARAMETER")
+    fun onStartBasicActivity(view: View) {
+        Log.d(LOG_TAG, "** starting BasicActivity")
+
+        // Start an Activity with the default options in the 'singleTask' launch mode as defined in
+        // the AndroidManifest.xml.
+        startActivity(Intent(this, BasicActivity::class.java))
+    }
+
+    @Suppress("UNUSED_PARAMETER")
+    fun onStartCustomConfigurationActivity(view: View) {
+        Log.d(LOG_TAG, "** starting CustomConfigurationChangeActivity")
+
+        // Start an Activity that handles all configuration changes itself.
+        startActivity(Intent(this, CustomConfigurationChangeActivity::class.java))
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/AdjacentActivity.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/AdjacentActivity.kt
new file mode 100644
index 0000000..fb8206e
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/AdjacentActivity.kt
@@ -0,0 +1,37 @@
+/*
+ * 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 com.android.multiwindowplayground.activities
+
+import android.os.Bundle
+import com.android.multiwindowplayground.R
+
+/**
+ * This Activity is to be launched adjacent to another Activity using the
+ * [android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT] flag.
+ *
+ * @see [com.android.multiwindowplayground.MainActivity.onStartAdjacentActivity]
+ */
+class AdjacentActivity : LoggingActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_logging)
+        setBackgroundColor(R.color.teal)
+        setDescription(R.string.activity_adjacent_description)
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/BasicActivity.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/BasicActivity.kt
new file mode 100644
index 0000000..cc7821a
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/BasicActivity.kt
@@ -0,0 +1,37 @@
+/*
+ * 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 com.android.multiwindowplayground.activities
+
+import android.os.Bundle
+import com.android.multiwindowplayground.R
+
+/**
+ * This activity is the most basic, simple use case and is to be launched without any special
+ * flags or settings.
+ *
+ * @see [com.android.multiwindowplayground.MainActivity.onStartBasicActivity]
+ */
+class BasicActivity : LoggingActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_logging)
+        setDescription(R.string.activity_description_basic)
+        setBackgroundColor(R.color.gray)
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/CustomConfigurationChangeActivity.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/CustomConfigurationChangeActivity.kt
new file mode 100644
index 0000000..5e48f2e
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/CustomConfigurationChangeActivity.kt
@@ -0,0 +1,38 @@
+/*
+ * 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 com.android.multiwindowplayground.activities
+
+import android.os.Bundle
+import com.android.multiwindowplayground.R
+
+/**
+ * This activity handles configuration changes itself. The list of configuration changes that are
+ * supported is defined in its AndroidManifest definition. Each configuration change triggers a
+ * call to [onConfigurationChanged], which is logged in the [LoggingActivity].
+ *
+ * @see [com.android.multiwindowplayground.MainActivity.onStartCustomConfigurationActivity]
+ */
+class CustomConfigurationChangeActivity : LoggingActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_logging)
+        setBackgroundColor(R.color.cyan)
+        setDescription(R.string.activity_custom_description)
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/LaunchBoundsActivity.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/LaunchBoundsActivity.kt
new file mode 100644
index 0000000..50838c6
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/LaunchBoundsActivity.kt
@@ -0,0 +1,37 @@
+/*
+ * 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 com.android.multiwindowplayground.activities
+
+import android.os.Bundle
+import com.android.multiwindowplayground.R
+
+/**
+ * In free-form mode, this activity is to be launched within a defined bounds on screen.
+ * This property is set as part of the Intent that starts this activity.
+ *
+ * @see [com.android.multiwindowplayground.MainActivity.onStartLaunchBoundsActivity]
+ */
+class LaunchBoundsActivity : LoggingActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_logging)
+        setBackgroundColor(R.color.lime)
+        setDescription(R.string.activity_bounds_description)
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/LoggingActivity.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/LoggingActivity.kt
new file mode 100644
index 0000000..313bb10
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/LoggingActivity.kt
@@ -0,0 +1,158 @@
+/*
+ * 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 com.android.multiwindowplayground.activities
+
+import android.content.res.Configuration
+import android.os.Bundle
+import android.os.PersistableBundle
+import android.support.annotation.ColorRes
+import android.support.annotation.StringRes
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import android.widget.TextView
+import com.android.multiwindowplayground.R
+import com.android.multiwindowplayground.logger.Log
+import com.android.multiwindowplayground.logger.LogFragment
+import com.android.multiwindowplayground.logger.LogWrapper
+import com.android.multiwindowplayground.logger.MessageOnlyLogFilter
+
+const val LOG_TAG = "LoggingActivity"
+
+/**
+ * Activity that logs all key lifecycle callbacks to [Log].
+ * Output is also logged to the UI into a [LogFragment] through [initializeLogging] and
+ * [stopLogging].
+ */
+abstract class LoggingActivity : AppCompatActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        Log.d(LOG_TAG, "onCreate")
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
+        super.onCreate(savedInstanceState, persistentState)
+        Log.d(LOG_TAG, "onCreatePersistable")
+    }
+
+    override fun onStart() {
+        super.onStart()
+        // Start logging to UI.
+        initializeLogging()
+
+        Log.d(LOG_TAG, "onStart")
+    }
+
+    override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
+        super.onRestoreInstanceState(savedInstanceState)
+        Log.d(LOG_TAG, "onRestoreInstanceState")
+    }
+
+    override fun onRestoreInstanceState(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
+        super.onRestoreInstanceState(savedInstanceState, persistentState)
+        Log.d(LOG_TAG, "onRestoreInstanceStatePersistable")
+    }
+
+    override fun onResume() {
+        super.onResume()
+        Log.d(LOG_TAG, "onResume")
+    }
+
+    override fun onPostCreate(savedInstanceState: Bundle?) {
+        super.onPostCreate(savedInstanceState)
+        Log.d(LOG_TAG, "onPostCreate")
+    }
+
+    override fun onPostCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
+        super.onPostCreate(savedInstanceState, persistentState)
+        Log.d(LOG_TAG, "onPostCreate")
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        Log.d(LOG_TAG, "onConfigurationChanged: $newConfig")
+    }
+
+    override fun onMultiWindowModeChanged(isInMultiWindowMode: Boolean, newConfig: Configuration?) {
+        super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig)
+        Log.d(LOG_TAG, "onMultiWindowModeChanged: $isInMultiWindowMode")
+    }
+
+    override fun onSaveInstanceState(outState: Bundle?) {
+        super.onSaveInstanceState(outState)
+        Log.d(LOG_TAG, "onSaveInstanceState")
+    }
+
+    override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
+        super.onSaveInstanceState(outState, outPersistentState)
+        Log.d(LOG_TAG, "onSaveInstanceStatePersistable")
+    }
+
+    override fun onPause() {
+        super.onPause()
+        Log.d(LOG_TAG, "onPause")
+    }
+
+    override fun onStop() {
+        super.onStop()
+        // Stop logging to UI when this activity is stopped.
+        stopLogging()
+
+        Log.d(LOG_TAG, "onStop")
+    }
+
+    override fun onRestart() {
+        super.onRestart()
+        Log.d(LOG_TAG, "onRestart")
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        Log.d(LOG_TAG, "onDestroy")
+    }
+
+    /**
+     * Set up targets to receive log data
+     */
+    private fun initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        val logWrapper = LogWrapper()
+        Log.logNode = logWrapper
+
+        // Filter strips out everything except the message text.
+        val msgFilter = MessageOnlyLogFilter()
+        logWrapper.next = msgFilter
+
+        // On screen logging via a fragment with a TextView.
+        val logFragment = supportFragmentManager.findFragmentById(R.id.log_fragment) as LogFragment
+        msgFilter.next = logFragment.logView
+    }
+
+    private fun stopLogging() {
+        Log.logNode = null
+    }
+
+    protected fun setDescription(@StringRes textId: Int) {
+        findViewById<TextView>(R.id.description).setText(textId)
+    }
+
+    protected fun setBackgroundColor(@ColorRes colorId: Int) {
+        findViewById<View>(R.id.scrollview).setBackgroundResource(colorId)
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/MinimumSizeActivity.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/MinimumSizeActivity.kt
new file mode 100644
index 0000000..d91cd47
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/MinimumSizeActivity.kt
@@ -0,0 +1,36 @@
+/*
+ * 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 com.android.multiwindowplayground.activities
+
+import android.os.Bundle
+import com.android.multiwindowplayground.R
+
+/**
+ * This Activity has a minimum size defined in the AndroidManifest.
+ *
+ * @see [com.android.multiwindowplayground.MainActivity.onStartMinimumSizeActivity]
+ */
+class MinimumSizeActivity : LoggingActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_logging)
+        setBackgroundColor(R.color.pink)
+        setDescription(R.string.activity_minimum_description)
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/UnresizableActivity.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/UnresizableActivity.kt
new file mode 100644
index 0000000..285fb82
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/activities/UnresizableActivity.kt
@@ -0,0 +1,38 @@
+/*
+ * 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 com.android.multiwindowplayground.activities
+
+import android.os.Bundle
+import com.android.multiwindowplayground.R
+
+/**
+ * This Activity is defined as unresizable in the AndroidManifest.
+ * This means that this activity is always launched full screen and will not be resized by the
+ * system.
+ *
+ * @see [com.android.multiwindowplayground.MainActivity.onStartUnresizableClick]
+ */
+class UnresizableActivity : LoggingActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_logging)
+        setBackgroundColor(R.color.purple)
+        setDescription(R.string.activity_description_unresizable)
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/Log.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/Log.kt
new file mode 100755
index 0000000..2bce5c8
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/Log.kt
@@ -0,0 +1,59 @@
+/*
+ * 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 com.android.multiwindowplayground.logger
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ *
+ * When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for [android.util.Log].
+ * Most of the methods in this class serve only to map a method call in Log to its equivalent
+ * in LogNode.
+ */
+object Log {
+
+    internal val NONE = -1
+
+    // Use the native value from Android's native logging facilities for easy migration and interop.
+    private val DEBUG = android.util.Log.DEBUG
+
+    // Stores the beginning of the LogNode topology.
+    internal var logNode: LogNode? = null
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag      Tag for for the log data. Can be used to organize log statements.
+     * @param msg      The actual message to be logged. The actual message to be logged.
+     */
+    private fun println(priority: Int, tag: String, msg: String) {
+        logNode?.println(priority, tag, msg, null)
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    fun d(tag: String, msg: String) {
+        println(DEBUG, tag, msg)
+    }
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogFragment.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogFragment.kt
new file mode 100755
index 0000000..2014d0e
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogFragment.kt
@@ -0,0 +1,90 @@
+/*
+ * 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 com.android.multiwindowplayground.logger
+
+import android.graphics.Typeface
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.support.v4.app.FragmentActivity
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.widget.ScrollView
+
+/**
+ * Simple fragment which contains a [LogView] and is used to output log data it receives through the
+ * [LogNode] interface.
+ */
+class LogFragment : Fragment() {
+
+    internal lateinit var logView: LogView
+    private lateinit var scrollView: ScrollView
+
+    private fun inflateViews(): View {
+        val scrollParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+        val logParams = ViewGroup.LayoutParams(scrollParams).apply {
+            height = WRAP_CONTENT
+        }
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        val paddingDips = 16
+        val scale = resources.displayMetrics.density.toDouble()
+        val paddingPixels = (paddingDips * scale + .5).toInt()
+
+        logView = LogView(activity as FragmentActivity).apply {
+            setTextAppearance(android.R.style.TextAppearance_Material_Medium)
+            layoutParams = logParams
+            isClickable = true
+            isFocusable = true
+            typeface = Typeface.create("monospace", Typeface.NORMAL)
+            setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels)
+            compoundDrawablePadding = paddingPixels
+            gravity = Gravity.BOTTOM
+        }
+
+        scrollView = ScrollView(activity).apply {
+            layoutParams = scrollParams
+            addView(logView)
+        }
+        return scrollView
+    }
+
+    override fun onCreateView(
+            inflater: LayoutInflater,
+            container: ViewGroup?,
+            savedInstanceState: Bundle?
+    ): View? {
+        val result = inflateViews()
+
+        logView.addTextChangedListener(object : TextWatcher {
+            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+
+            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
+
+            override fun afterTextChanged(s: Editable) {
+                scrollView.run { post { smoothScrollTo(0, scrollView.bottom + logView.height) }}
+            }
+        })
+        return result
+    }
+
+}
\ No newline at end of file
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogNode.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogNode.kt
new file mode 100755
index 0000000..a9c23f9
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogNode.kt
@@ -0,0 +1,41 @@
+/*
+ * 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 com.android.multiwindowplayground.logger
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     *
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag      Tag for for the log data.  Can be used to organize log statements.
+     * @param msg      The actual message to be logged. The actual message to be logged.
+     * @param tr       If an exception was thrown, this can be sent along for the logging
+     *                 facilities to extract and print useful information.
+     */
+    fun println(priority: Int, tag: String?, msg: String, tr: Throwable?)
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogView.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogView.kt
new file mode 100755
index 0000000..22488dc
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogView.kt
@@ -0,0 +1,90 @@
+/*
+ * 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 com.android.multiwindowplayground.logger
+
+import android.app.Activity
+import android.content.Context
+
+/**
+ * Simple TextView which is used to output log data received through the LogNode interface.
+ */
+class LogView(context: Context) : android.support.v7.widget.AppCompatTextView(context), LogNode {
+
+    // The next LogNode in the chain.
+    private var next: LogNode? = null
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     *
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag      Tag for for the log data.  Can be used to organize log statements.
+     * @param msg      The actual message to be logged. The actual message to be logged.
+     * @param tr       If an exception was thrown, this can be sent along for the logging
+     *                 facilities to extract and print useful information.
+     */
+    override fun println(priority: Int, tag: String?, msg: String, tr: Throwable?) {
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        val priorityStr = when (priority) {
+            android.util.Log.VERBOSE -> "VERBOSE"
+            android.util.Log.DEBUG -> "DEBUG"
+            android.util.Log.INFO -> "INFO"
+            android.util.Log.WARN -> "WARN"
+            android.util.Log.ERROR -> "ERROR"
+            android.util.Log.ASSERT -> "ASSERT"
+            else -> "VERBOSE"
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        var exceptionStr: String? = null
+        if (tr != null) exceptionStr = android.util.Log.getStackTraceString(tr)
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        val delimiter = "\t"
+        val outputBuilder = StringBuilder().also {
+            appendIfNotNullOrEmpty(it, priorityStr, delimiter)
+            appendIfNotNullOrEmpty(it, tag, delimiter)
+            appendIfNotNullOrEmpty(it, msg, delimiter)
+            appendIfNotNullOrEmpty(it, exceptionStr, delimiter)
+        }
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        (context as Activity).runOnUiThread(Thread(Runnable {
+            // Display the text we just generated within the LogView as a new line of log data.
+            append("\n$outputBuilder")
+        }))
+
+        next?.println(priority, tag, msg, tr)
+    }
+
+    /**
+     * Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same statement over and over.
+     *
+     * @param source    StringBuilder containing the text to append to.
+     * @param addStr    The String to append
+     * @param delimiter The String to separate the source and appended strings.
+     */
+    private fun appendIfNotNullOrEmpty(source: StringBuilder, addStr: String?, delimiter: String) {
+        if (addStr.isNullOrEmpty()) return
+        source.append(addStr).append(delimiter)
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogWrapper.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogWrapper.kt
new file mode 100755
index 0000000..046b743
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/LogWrapper.kt
@@ -0,0 +1,52 @@
+/*
+ * 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 com.android.multiwindowplayground.logger
+
+import android.util.Log
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+class LogWrapper : LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    internal var next: LogNode? = null
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag      Tag for for the log data.  Can be used to organize log statements.
+     * @param msg      The actual message to be logged. The actual message to be logged.
+     * @param tr       If an exception was thrown, this can be sent along for the logging
+     *                 facilities to extract and print useful information.
+     */
+    override fun println(priority: Int, tag: String?, msg: String, tr: Throwable?) {
+
+        // If an exception was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) msg.plus("\n${Log.getStackTraceString(tr)}")
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, msg)
+
+        // If this isn't the last node in the chain, move things along.
+        next?.println(priority, tag, msg, tr)
+    }
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/MessageOnlyLogFilter.kt b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/MessageOnlyLogFilter.kt
new file mode 100755
index 0000000..a3f1e62
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/java/com/android/multiwindowplayground/logger/MessageOnlyLogFilter.kt
@@ -0,0 +1,32 @@
+/*
+ * 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 com.android.multiwindowplayground.logger
+
+/**
+ * Simple [LogNode] filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata
+ * displayed, just easy-to-read message updates as they're happening.
+ */
+class MessageOnlyLogFilter : LogNode {
+
+    var next: LogNode? = null
+
+    override fun println(priority: Int, tag: String?, msg: String, tr: Throwable?) {
+        next?.println(Log.NONE, null, msg, null)
+    }
+
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/layout/activity_logging.xml b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/layout/activity_logging.xml
new file mode 100644
index 0000000..2389e12
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/layout/activity_logging.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<!-- This layout contains a TextView and a LogFragment that logs some text to the screen. -->
+<LinearLayout android:id="@+id/layout"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/white"
+    android:orientation="vertical">
+
+    <ScrollView
+        android:id="@+id/scrollview"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_gravity="top"
+        android:layout_weight="0.75">
+
+        <TextView
+            android:id="@+id/description"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:paddingBottom="@dimen/activity_vertical_margin"
+            android:paddingLeft="@dimen/activity_horizontal_margin"
+            android:paddingRight="@dimen/activity_horizontal_margin"
+            android:paddingTop="@dimen/activity_vertical_margin"
+            android:textColor="@color/white" />
+    </ScrollView>
+
+    <include
+        layout="@layout/logging"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_gravity="bottom"
+        android:layout_weight="0.25" />
+</LinearLayout>
\ No newline at end of file
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/layout/activity_main.xml b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..7c405a3
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/layout/activity_main.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:orientation="vertical"
+    android:background="@color/lightgray">
+
+    <ScrollView xmlns:tools="http://schemas.android.com/tools"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="0.75"
+        android:background="@color/white"
+        android:layout_gravity="top"
+        android:id="@+id/scrollview"
+        tools:context="com.android.multiwindowplayground.MainActivity">
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingBottom="@dimen/activity_vertical_margin"
+            android:paddingLeft="@dimen/activity_horizontal_margin"
+            android:paddingRight="@dimen/activity_horizontal_margin"
+            android:paddingTop="@dimen/activity_vertical_margin"
+            android:orientation="vertical">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/introduction_title"
+                android:textSize="@dimen/text_view_text_size" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/warning_multiwindow_disabled"
+                android:visibility="gone"
+                tools:visibility="visible"
+                style="@style/TextWarning"
+                android:paddingTop="@dimen/content_vertical_dividing_padding"
+                android:paddingBottom="@dimen/content_vertical_dividing_padding"
+                android:text="@string/multi_window_sample_action" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/description"
+                android:text="@string/sample_introduction" />
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/button_start_basic"
+                android:onClick="onStartBasicActivity"
+                android:text="@string/start_default" />
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/start_unresizable"
+                android:onClick="onStartUnresizableClick"
+                android:text="@string/start_unresizable" />
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/start_adjacent"
+                android:onClick="onStartAdjacentActivity"
+                android:text="@string/start_adjacent" />
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/start_customconfiguration"
+                android:onClick="onStartCustomConfigurationActivity"
+                android:text="@string/start_custom_activity" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingTop="@dimen/content_vertical_dividing_padding"
+                android:text="@string/sample_freeform_introduction" />
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/start_minimumsize"
+                android:onClick="onStartMinimumSizeActivity"
+                android:text="@string/start_minimum" />
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/start_launchbounds"
+                android:onClick="onStartLaunchBoundsActivity"
+                android:text="@string/start_bounds" />
+
+        </LinearLayout>
+    </ScrollView>
+
+    <include
+        layout="@layout/logging"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_gravity="bottom"
+        android:layout_weight="0.25" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/layout/logging.xml b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/layout/logging.xml
new file mode 100644
index 0000000..abd9018
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/layout/logging.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<fragment xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:id="@+id/log_fragment"
+    android:name="com.android.multiwindowplayground.logger.LogFragment" />
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-hdpi/ic_launcher.png b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100755
index 0000000..a150a5c
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-mdpi/ic_launcher.png b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100755
index 0000000..1a482dd
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-xhdpi/ic_launcher.png b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..148db37
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..7c5c6a4
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100755
index 0000000..944fc54
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values-w820dp/dimens.xml b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..e2ec117
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/colors.xml b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..18da4e1
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/colors.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+
+    <color name="purple">#512DA8</color>
+    <color name="pink">#C2185B</color>
+    <color name="teal">#00695C</color>
+    <color name="lime">#9E9D24</color>
+    <color name="gray">#424242</color>
+    <color name="lightgray">#F5F5F5</color>
+    <color name="cyan">#00838F</color>
+
+    <color name="white">#FFFFFF</color>
+</resources>
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/dimens.xml b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..a349e62
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="content_vertical_dividing_padding">16dp</dimen>
+    <dimen name="text_view_text_size">30sp</dimen>
+</resources>
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/strings.xml b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..7bd6fbd
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/strings.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="app_name">MultiWindow Playground</string>
+    <string name="introduction_title">Multiwindow Playground</string>
+    <string name="sample_introduction">This sample demonstrates the use of the multi-window API
+        available in Android N.\nFirst, switch this app into
+        <b>split-screen mode</b>
+        (for example by long-pressing the recents button). Each button below starts a new activity
+        with special flags.\n<b>See the files MainActivity.kt and AndroidManifest.xml for
+        implementation details.</b>
+    </string>
+    <string name="sample_freeform_introduction">The buttons below demonstrate features only
+        available in <b>free-form multi-window mode</b>.</string>
+    <string name="start_default">Start basic, default Activity</string>
+    <string name="start_unresizable">Start unresizable Activity</string>
+    <string name="start_adjacent">Start Activity adjacent</string>
+    <string name="start_minimum">Start Activity with minimum size</string>
+    <string name="start_bounds">Start Activity with launch bounds</string>
+    <string name="start_custom_activity">Start activity that handles configuration changes.</string>
+
+    <string name="activity_description_basic">This Activity was launched in a new task without any
+        additional flags or options.
+    </string>
+    <string name="activity_description_unresizable">This activity is set as unresizable in the
+        AndroidManifest. This is done by setting the <i>resizeableActivity</i> property to
+        <i>false</i> for this activity.
+    </string>
+    <string name="activity_adjacent_description">This activity was launched with the flag
+        <b>Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT</b>.\n\nIf possible, it has been launched into the
+        adjacent area from the activity that started it.\nThis is only a hint to the system. For
+        example - if the application is not in split-screen mode, it will be launched full-screen.
+        If it is launched in the same task as the initial Activity, it will retain its activity
+        properties and its location.
+    </string>
+    <string name="activity_custom_description">This activity handles configuration changes
+        itself.\n\nIn the AndroidManifest, this activity has been configured to receive callbacks
+        for <b>screenSize|smallestScreenSize|screenLayout|orientation</b>
+        changes.\nTry resizing this activity to different sizes to see which configuration
+        properties change.
+    </string>
+    <string name="activity_bounds_description">This activity has been launched with a launch bounds
+        set in its intent. The bounds define the area into which the activity should be launched.
+        \n\nNote that this flag only applies in free-form mode.
+    </string>
+    <string name="activity_minimum_description">This activity has a minimum size.\nIt was launched
+        into the top/end corner with a a default size of 750dp by 500dp, with a minimum size of
+        750dp as defined in its <b>layout attribute in the AndroidManifest definition</b>.
+        \n\nNote that this Activity was launched in a different task, otherwise the properties from
+        the Activity that launched this one would have been applied.
+    </string>
+    <string name="multi_window_sample_action">Enable multi-window mode to see this sample in
+        action!</string>
+</resources>
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/styles.xml b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..e62ba34
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/Application/src/main/res/values/styles.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="MultiWindowSampleTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+
+        <!-- Drawable to use in the background while the window is resizing on Android N. -->
+        <item name="android:windowBackgroundFallback">@color/colorAccent</item>
+        <item name="android:windowBackground">@color/colorAccent</item>
+    </style>
+
+    <style name="TextWarning" parent="TextAppearance.AppCompat.Medium">
+
+    </style>
+
+
+</resources>
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/README.md b/ui/window/MultiWindowPlayground/kotlinApp/README.md
new file mode 100644
index 0000000..89b6e2f
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/README.md
@@ -0,0 +1,94 @@
+Android MultiWindowPlayground Sample (Kotlin)
+=============================================
+
+This sample demonstrates the use of the multi-window API available
+in Android N. It shows the use of new Intent flags and
+AndroidManifest properties to define the multi-window behavior.
+Switch the sample app into multi-window mode to see how it affects
+the lifecycle and behavior of the app.
+
+Introduction
+------------
+
+Android N introduces new APIs to support multiple activities
+to be displayed at the same time.
+
+Activities that are started within the same task stack
+inherit their multiwindow properties from the activity that fired
+off the intent. The following features are available when an activity
+has been launched into a new task stack.
+
+An activity can be set as not resizable through the
+`android:resizableActivity` property in the AndroidManifest. All
+applications targeting Android N or above are resizable by default.
+
+In split-screen mode, an activity can be started adjacent to the
+launching activity by setting the
+`Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT` flag in its intent.
+
+Sometimes activities may choose to handle configuration changes
+themselves (for example for games or OpenGL-based applications). In this
+case, setting
+`android:configChanges=screenSize|smallestScreenSize|screenLayout|orientation`
+in the AndroidManifest definition of the activity enables callbacks for
+all configuration changes that may occur during multi-window use for the
+Activity. See [Handling Runtime Changes][1].
+
+In freeform mode (where applications can be freely resized), activities
+can be started within a certain area of the screen using the
+`ActivityOptions#setLaunchBounds` call.
+
+Alternatively, the preferred and minimum sizes can be set in a new
+`layout` property in the AndroidManifest.
+
+
+[1]: https://developer.android.com/guide/topics/resources/runtime-changes.html
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Support Repository
+
+Screenshots
+-------------
+
+<img src="screenshots/main.png" height="400" alt="Screenshot"/>
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-MultiWindowPlayground
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2017 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements.  See the NOTICE file distributed with this work for
+additional information regarding copyright ownership.  The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License.  You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/build.gradle b/ui/window/MultiWindowPlayground/kotlinApp/build.gradle
new file mode 100644
index 0000000..6b3af00
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/build.gradle
@@ -0,0 +1,22 @@
+buildscript {
+    ext.kotlin_version = '1.2.0'
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/ui/window/MultiWindowPlayground/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/ui/window/MultiWindowPlayground/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..71a62b5
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Dec 28 10:00:20 PST 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
\ No newline at end of file
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/gradlew b/ui/window/MultiWindowPlayground/kotlinApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/gradlew.bat b/ui/window/MultiWindowPlayground/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/screenshots/icon-web.png b/ui/window/MultiWindowPlayground/kotlinApp/screenshots/icon-web.png
new file mode 100755
index 0000000..8d99c12
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/screenshots/icon-web.png
Binary files differ
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/screenshots/main.png b/ui/window/MultiWindowPlayground/kotlinApp/screenshots/main.png
new file mode 100644
index 0000000..d922200
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/screenshots/main.png
Binary files differ
diff --git a/ui/window/MultiWindowPlayground/kotlinApp/settings.gradle b/ui/window/MultiWindowPlayground/kotlinApp/settings.gradle
new file mode 100644
index 0000000..9464a35
--- /dev/null
+++ b/ui/window/MultiWindowPlayground/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'Application'
diff --git a/views/EmojiCompat/build.gradle b/views/EmojiCompat/build.gradle
index 5811ab0..318c4c0 100644
--- a/views/EmojiCompat/build.gradle
+++ b/views/EmojiCompat/build.gradle
@@ -19,7 +19,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/views/EmojiCompat/gradle/wrapper/gradle-wrapper.properties b/views/EmojiCompat/gradle/wrapper/gradle-wrapper.properties
index 93a1579..947a175 100644
--- a/views/EmojiCompat/gradle/wrapper/gradle-wrapper.properties
+++ b/views/EmojiCompat/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/views/EmojiCompat/kotlinApp/build.gradle b/views/EmojiCompat/kotlinApp/build.gradle
index f25c0d2..2c5482b 100644
--- a/views/EmojiCompat/kotlinApp/build.gradle
+++ b/views/EmojiCompat/kotlinApp/build.gradle
@@ -19,7 +19,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/views/EmojiCompat/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/views/EmojiCompat/kotlinApp/gradle/wrapper/gradle-wrapper.properties
index 93a1579..947a175 100644
--- a/views/EmojiCompat/kotlinApp/gradle/wrapper/gradle-wrapper.properties
+++ b/views/EmojiCompat/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/views/TextLinkify/gradle/wrapper/gradle-wrapper.properties b/views/TextLinkify/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/views/TextLinkify/gradle/wrapper/gradle-wrapper.properties
+++ b/views/TextLinkify/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/AgendaData/LICENSE b/wearable/wear/AgendaData/LICENSE
index 4f22946..d5cf8f3 100644
--- a/wearable/wear/AgendaData/LICENSE
+++ b/wearable/wear/AgendaData/LICENSE
@@ -201,447 +201,3 @@
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-
-All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav 
-and *.ogg) are licensed under the CC-BY-NC license. All other files are 
-licensed under the Apache 2 license.
-
-CC-BY-NC License
-----------------
-
-Attribution-NonCommercial-ShareAlike 4.0 International
-
-=======================================================================
-
-Creative Commons Corporation ("Creative Commons") is not a law firm and
-does not provide legal services or legal advice. Distribution of
-Creative Commons public licenses does not create a lawyer-client or
-other relationship. Creative Commons makes its licenses and related
-information available on an "as-is" basis. Creative Commons gives no
-warranties regarding its licenses, any material licensed under their
-terms and conditions, or any related information. Creative Commons
-disclaims all liability for damages resulting from their use to the
-fullest extent possible.
-
-Using Creative Commons Public Licenses
-
-Creative Commons public licenses provide a standard set of terms and
-conditions that creators and other rights holders may use to share
-original works of authorship and other material subject to copyright
-and certain other rights specified in the public license below. The
-following considerations are for informational purposes only, are not
-exhaustive, and do not form part of our licenses.
-
-     Considerations for licensors: Our public licenses are
-     intended for use by those authorized to give the public
-     permission to use material in ways otherwise restricted by
-     copyright and certain other rights. Our licenses are
-     irrevocable. Licensors should read and understand the terms
-     and conditions of the license they choose before applying it.
-     Licensors should also secure all rights necessary before
-     applying our licenses so that the public can reuse the
-     material as expected. Licensors should clearly mark any
-     material not subject to the license. This includes other CC-
-     licensed material, or material used under an exception or
-     limitation to copyright. More considerations for licensors:
-	wiki.creativecommons.org/Considerations_for_licensors
-
-     Considerations for the public: By using one of our public
-     licenses, a licensor grants the public permission to use the
-     licensed material under specified terms and conditions. If
-     the licensor's permission is not necessary for any reason--for
-     example, because of any applicable exception or limitation to
-     copyright--then that use is not regulated by the license. Our
-     licenses grant only permissions under copyright and certain
-     other rights that a licensor has authority to grant. Use of
-     the licensed material may still be restricted for other
-     reasons, including because others have copyright or other
-     rights in the material. A licensor may make special requests,
-     such as asking that all changes be marked or described.
-     Although not required by our licenses, you are encouraged to
-     respect those requests where reasonable. More_considerations
-     for the public: 
-	wiki.creativecommons.org/Considerations_for_licensees
-
-=======================================================================
-
-Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
-Public License
-
-By exercising the Licensed Rights (defined below), You accept and agree
-to be bound by the terms and conditions of this Creative Commons
-Attribution-NonCommercial-ShareAlike 4.0 International Public License
-("Public License"). To the extent this Public License may be
-interpreted as a contract, You are granted the Licensed Rights in
-consideration of Your acceptance of these terms and conditions, and the
-Licensor grants You such rights in consideration of benefits the
-Licensor receives from making the Licensed Material available under
-these terms and conditions.
-
-
-Section 1 -- Definitions.
-
-  a. Adapted Material means material subject to Copyright and Similar
-     Rights that is derived from or based upon the Licensed Material
-     and in which the Licensed Material is translated, altered,
-     arranged, transformed, or otherwise modified in a manner requiring
-     permission under the Copyright and Similar Rights held by the
-     Licensor. For purposes of this Public License, where the Licensed
-     Material is a musical work, performance, or sound recording,
-     Adapted Material is always produced where the Licensed Material is
-     synched in timed relation with a moving image.
-
-  b. Adapter's License means the license You apply to Your Copyright
-     and Similar Rights in Your contributions to Adapted Material in
-     accordance with the terms and conditions of this Public License.
-
-  c. BY-NC-SA Compatible License means a license listed at
-     creativecommons.org/compatiblelicenses, approved by Creative
-     Commons as essentially the equivalent of this Public License.
-
-  d. Copyright and Similar Rights means copyright and/or similar rights
-     closely related to copyright including, without limitation,
-     performance, broadcast, sound recording, and Sui Generis Database
-     Rights, without regard to how the rights are labeled or
-     categorized. For purposes of this Public License, the rights
-     specified in Section 2(b)(1)-(2) are not Copyright and Similar
-     Rights.
-
-  e. Effective Technological Measures means those measures that, in the
-     absence of proper authority, may not be circumvented under laws
-     fulfilling obligations under Article 11 of the WIPO Copyright
-     Treaty adopted on December 20, 1996, and/or similar international
-     agreements.
-
-  f. Exceptions and Limitations means fair use, fair dealing, and/or
-     any other exception or limitation to Copyright and Similar Rights
-     that applies to Your use of the Licensed Material.
-
-  g. License Elements means the license attributes listed in the name
-     of a Creative Commons Public License. The License Elements of this
-     Public License are Attribution, NonCommercial, and ShareAlike.
-
-  h. Licensed Material means the artistic or literary work, database,
-     or other material to which the Licensor applied this Public
-     License.
-
-  i. Licensed Rights means the rights granted to You subject to the
-     terms and conditions of this Public License, which are limited to
-     all Copyright and Similar Rights that apply to Your use of the
-     Licensed Material and that the Licensor has authority to license.
-
-  j. Licensor means the individual(s) or entity(ies) granting rights
-     under this Public License.
-
-  k. NonCommercial means not primarily intended for or directed towards
-     commercial advantage or monetary compensation. For purposes of
-     this Public License, the exchange of the Licensed Material for
-     other material subject to Copyright and Similar Rights by digital
-     file-sharing or similar means is NonCommercial provided there is
-     no payment of monetary compensation in connection with the
-     exchange.
-
-  l. Share means to provide material to the public by any means or
-     process that requires permission under the Licensed Rights, such
-     as reproduction, public display, public performance, distribution,
-     dissemination, communication, or importation, and to make material
-     available to the public including in ways that members of the
-     public may access the material from a place and at a time
-     individually chosen by them.
-
-  m. Sui Generis Database Rights means rights other than copyright
-     resulting from Directive 96/9/EC of the European Parliament and of
-     the Council of 11 March 1996 on the legal protection of databases,
-     as amended and/or succeeded, as well as other essentially
-     equivalent rights anywhere in the world.
-
-  n. You means the individual or entity exercising the Licensed Rights
-     under this Public License. Your has a corresponding meaning.
-
-
-Section 2 -- Scope.
-
-  a. License grant.
-
-       1. Subject to the terms and conditions of this Public License,
-          the Licensor hereby grants You a worldwide, royalty-free,
-          non-sublicensable, non-exclusive, irrevocable license to
-          exercise the Licensed Rights in the Licensed Material to:
-
-            a. reproduce and Share the Licensed Material, in whole or
-               in part, for NonCommercial purposes only; and
-
-            b. produce, reproduce, and Share Adapted Material for
-               NonCommercial purposes only.
-
-       2. Exceptions and Limitations. For the avoidance of doubt, where
-          Exceptions and Limitations apply to Your use, this Public
-          License does not apply, and You do not need to comply with
-          its terms and conditions.
-
-       3. Term. The term of this Public License is specified in Section
-          6(a).
-
-       4. Media and formats; technical modifications allowed. The
-          Licensor authorizes You to exercise the Licensed Rights in
-          all media and formats whether now known or hereafter created,
-          and to make technical modifications necessary to do so. The
-          Licensor waives and/or agrees not to assert any right or
-          authority to forbid You from making technical modifications
-          necessary to exercise the Licensed Rights, including
-          technical modifications necessary to circumvent Effective
-          Technological Measures. For purposes of this Public License,
-          simply making modifications authorized by this Section 2(a)
-          (4) never produces Adapted Material.
-
-       5. Downstream recipients.
-
-            a. Offer from the Licensor -- Licensed Material. Every
-               recipient of the Licensed Material automatically
-               receives an offer from the Licensor to exercise the
-               Licensed Rights under the terms and conditions of this
-               Public License.
-
-            b. Additional offer from the Licensor -- Adapted Material.
-               Every recipient of Adapted Material from You
-               automatically receives an offer from the Licensor to
-               exercise the Licensed Rights in the Adapted Material
-               under the conditions of the Adapter's License You apply.
-
-            c. No downstream restrictions. You may not offer or impose
-               any additional or different terms or conditions on, or
-               apply any Effective Technological Measures to, the
-               Licensed Material if doing so restricts exercise of the
-               Licensed Rights by any recipient of the Licensed
-               Material.
-
-       6. No endorsement. Nothing in this Public License constitutes or
-          may be construed as permission to assert or imply that You
-          are, or that Your use of the Licensed Material is, connected
-          with, or sponsored, endorsed, or granted official status by,
-          the Licensor or others designated to receive attribution as
-          provided in Section 3(a)(1)(A)(i).
-
-  b. Other rights.
-
-       1. Moral rights, such as the right of integrity, are not
-          licensed under this Public License, nor are publicity,
-          privacy, and/or other similar personality rights; however, to
-          the extent possible, the Licensor waives and/or agrees not to
-          assert any such rights held by the Licensor to the limited
-          extent necessary to allow You to exercise the Licensed
-          Rights, but not otherwise.
-
-       2. Patent and trademark rights are not licensed under this
-          Public License.
-
-       3. To the extent possible, the Licensor waives any right to
-          collect royalties from You for the exercise of the Licensed
-          Rights, whether directly or through a collecting society
-          under any voluntary or waivable statutory or compulsory
-          licensing scheme. In all other cases the Licensor expressly
-          reserves any right to collect such royalties, including when
-          the Licensed Material is used other than for NonCommercial
-          purposes.
-
-
-Section 3 -- License Conditions.
-
-Your exercise of the Licensed Rights is expressly made subject to the
-following conditions.
-
-  a. Attribution.
-
-       1. If You Share the Licensed Material (including in modified
-          form), You must:
-
-            a. retain the following if it is supplied by the Licensor
-               with the Licensed Material:
-
-                 i. identification of the creator(s) of the Licensed
-                    Material and any others designated to receive
-                    attribution, in any reasonable manner requested by
-                    the Licensor (including by pseudonym if
-                    designated);
-
-                ii. a copyright notice;
-
-               iii. a notice that refers to this Public License;
-
-                iv. a notice that refers to the disclaimer of
-                    warranties;
-
-                 v. a URI or hyperlink to the Licensed Material to the
-                    extent reasonably practicable;
-
-            b. indicate if You modified the Licensed Material and
-               retain an indication of any previous modifications; and
-
-            c. indicate the Licensed Material is licensed under this
-               Public License, and include the text of, or the URI or
-               hyperlink to, this Public License.
-
-       2. You may satisfy the conditions in Section 3(a)(1) in any
-          reasonable manner based on the medium, means, and context in
-          which You Share the Licensed Material. For example, it may be
-          reasonable to satisfy the conditions by providing a URI or
-          hyperlink to a resource that includes the required
-          information.
-       3. If requested by the Licensor, You must remove any of the
-          information required by Section 3(a)(1)(A) to the extent
-          reasonably practicable.
-
-  b. ShareAlike.
-
-     In addition to the conditions in Section 3(a), if You Share
-     Adapted Material You produce, the following conditions also apply.
-
-       1. The Adapter's License You apply must be a Creative Commons
-          license with the same License Elements, this version or
-          later, or a BY-NC-SA Compatible License.
-
-       2. You must include the text of, or the URI or hyperlink to, the
-          Adapter's License You apply. You may satisfy this condition
-          in any reasonable manner based on the medium, means, and
-          context in which You Share Adapted Material.
-
-       3. You may not offer or impose any additional or different terms
-          or conditions on, or apply any Effective Technological
-          Measures to, Adapted Material that restrict exercise of the
-          rights granted under the Adapter's License You apply.
-
-
-Section 4 -- Sui Generis Database Rights.
-
-Where the Licensed Rights include Sui Generis Database Rights that
-apply to Your use of the Licensed Material:
-
-  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
-     to extract, reuse, reproduce, and Share all or a substantial
-     portion of the contents of the database for NonCommercial purposes
-     only;
-
-  b. if You include all or a substantial portion of the database
-     contents in a database in which You have Sui Generis Database
-     Rights, then the database in which You have Sui Generis Database
-     Rights (but not its individual contents) is Adapted Material,
-     including for purposes of Section 3(b); and
-
-  c. You must comply with the conditions in Section 3(a) if You Share
-     all or a substantial portion of the contents of the database.
-
-For the avoidance of doubt, this Section 4 supplements and does not
-replace Your obligations under this Public License where the Licensed
-Rights include other Copyright and Similar Rights.
-
-
-Section 5 -- Disclaimer of Warranties and Limitation of Liability.
-
-  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
-     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
-     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
-     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
-     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
-     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
-     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
-     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
-     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
-     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
-
-  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
-     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
-     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
-     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
-     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
-     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
-     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
-     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
-     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
-
-  c. The disclaimer of warranties and limitation of liability provided
-     above shall be interpreted in a manner that, to the extent
-     possible, most closely approximates an absolute disclaimer and
-     waiver of all liability.
-
-
-Section 6 -- Term and Termination.
-
-  a. This Public License applies for the term of the Copyright and
-     Similar Rights licensed here. However, if You fail to comply with
-     this Public License, then Your rights under this Public License
-     terminate automatically.
-
-  b. Where Your right to use the Licensed Material has terminated under
-     Section 6(a), it reinstates:
-
-       1. automatically as of the date the violation is cured, provided
-          it is cured within 30 days of Your discovery of the
-          violation; or
-
-       2. upon express reinstatement by the Licensor.
-
-     For the avoidance of doubt, this Section 6(b) does not affect any
-     right the Licensor may have to seek remedies for Your violations
-     of this Public License.
-
-  c. For the avoidance of doubt, the Licensor may also offer the
-     Licensed Material under separate terms or conditions or stop
-     distributing the Licensed Material at any time; however, doing so
-     will not terminate this Public License.
-
-  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
-     License.
-
-
-Section 7 -- Other Terms and Conditions.
-
-  a. The Licensor shall not be bound by any additional or different
-     terms or conditions communicated by You unless expressly agreed.
-
-  b. Any arrangements, understandings, or agreements regarding the
-     Licensed Material not stated herein are separate from and
-     independent of the terms and conditions of this Public License.
-
-
-Section 8 -- Interpretation.
-
-  a. For the avoidance of doubt, this Public License does not, and
-     shall not be interpreted to, reduce, limit, restrict, or impose
-     conditions on any use of the Licensed Material that could lawfully
-     be made without permission under this Public License.
-
-  b. To the extent possible, if any provision of this Public License is
-     deemed unenforceable, it shall be automatically reformed to the
-     minimum extent necessary to make it enforceable. If the provision
-     cannot be reformed, it shall be severed from this Public License
-     without affecting the enforceability of the remaining terms and
-     conditions.
-
-  c. No term or condition of this Public License will be waived and no
-     failure to comply consented to unless expressly agreed to by the
-     Licensor.
-
-  d. Nothing in this Public License constitutes or may be interpreted
-     as a limitation upon, or waiver of, any privileges and immunities
-     that apply to the Licensor or You, including from the legal
-     processes of any jurisdiction or authority.
-
-=======================================================================
-
-Creative Commons is not a party to its public licenses.
-Notwithstanding, Creative Commons may elect to apply one of its public
-licenses to material it publishes and in those instances will be
-considered the "Licensor." Except for the limited purpose of indicating
-that material is shared under a Creative Commons public license or as
-otherwise permitted by the Creative Commons policies published at
-creativecommons.org/policies, Creative Commons does not authorize the
-use of the trademark "Creative Commons" or any other trademark or logo
-of Creative Commons without its prior written consent including,
-without limitation, in connection with any unauthorized modifications
-to any of its public licenses or any other arrangements,
-understandings, or agreements concerning use of licensed material. For
-the avoidance of doubt, this paragraph does not form part of the public
-licenses.
-
-Creative Commons may be contacted at creativecommons.org.
-
diff --git a/wearable/wear/AgendaData/Wearable/src/main/AndroidManifest.xml b/wearable/wear/AgendaData/Wearable/src/main/AndroidManifest.xml
index 0d48310..6381e1a 100644
--- a/wearable/wear/AgendaData/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/AgendaData/Wearable/src/main/AndroidManifest.xml
@@ -17,15 +17,11 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.example.android.wearable.agendadata" >
 
-    <uses-sdk android:minSdkVersion="23"
-        android:targetSdkVersion="25" />
-
     <uses-feature android:name="android.hardware.type.watch" />
 
     <application
             android:icon="@drawable/ic_launcher"
-            android:label="@string/app_name"
-            >
+            android:label="@string/app_name">
 
         <meta-data
             android:name="com.google.android.wearable.standalone"
diff --git a/wearable/wear/AgendaData/Wearable/src/main/res/values/strings.xml b/wearable/wear/AgendaData/Wearable/src/main/res/values/strings.xml
index 10ef53c..ab4afd2 100644
--- a/wearable/wear/AgendaData/Wearable/src/main/res/values/strings.xml
+++ b/wearable/wear/AgendaData/Wearable/src/main/res/values/strings.xml
@@ -15,7 +15,7 @@
 -->
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name">Android Wear AgendaData Example Application</string>
+    <string name="app_name">Wear AgendaData Example Application</string>
     <string name="delete">Delete</string>
     <string name="desc_all_day">%s(All day)</string>
     <string name="desc_time_period">%1$s(%2$s - %3$s)</string>
diff --git a/wearable/wear/AgendaData/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/AgendaData/gradle/wrapper/gradle-wrapper.properties
index 7a7c466..f5d30b7 100644
--- a/wearable/wear/AgendaData/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/AgendaData/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/AgendaData/template-params.xml b/wearable/wear/AgendaData/template-params.xml
index 10fa0ea..63a6bda 100644
--- a/wearable/wear/AgendaData/template-params.xml
+++ b/wearable/wear/AgendaData/template-params.xml
@@ -23,11 +23,13 @@
     <package>com.example.android.wearable.agendadata</package>
 
     <minSdk>18</minSdk>
-    <targetSdkVersion>25</targetSdkVersion>
+    <targetSdkVersion>27</targetSdkVersion>
     <minSdkVersionWear>23</minSdkVersionWear>
-    <targetSdkVersionWear>25</targetSdkVersionWear>
+    <targetSdkVersionWear>27</targetSdkVersionWear>
+    <compileSdkVersionWear>27</compileSdkVersionWear>
 
-    <dependency>com.android.support:design:24.0.0</dependency>
+    <dependency>com.android.support:design:27.1.0</dependency>
+
 
     <wearable>
         <has_handheld_app>true</has_handheld_app>
@@ -36,6 +38,9 @@
     <strings>
         <intro>
             <![CDATA[
+            This sample is deprecated, please review the DataLayer sample to understand how to
+            transfer data between mobile and wear devices.
+
             Syncs calendar events to your wearable at the press of a button, using the Wearable
             DataApi to transmit data such as event time, description, and background image. The
             DataItems can be deleted individually via an action on the event notifications, or all
@@ -48,7 +53,7 @@
     <template src="base"/>
     <template src="Wear"/>
     <metadata>
-        <status>PUBLISHED</status>
+        <status>DEPRECATED</status>
         <categories>Wearable</categories>
         <technologies>Android</technologies>
         <languages>Java</languages>
@@ -71,6 +76,9 @@
         </description>
         <intro>
 <![CDATA[
+This sample is deprecated, please review the [DataLayer sample][3] to understand how to
+transfer data between mobile and wear devices.
+
 Using the Wearable [DataApi][1] allows to transmit data such as event time,
 description, and background image.
 
@@ -82,6 +90,7 @@
 
 [1]: https://developer.android.com/reference/com/google/android/gms/wearable/DataApi.html
 [2]: https://developer.android.com/reference/com/google/android/gms/wearable/DataItem.html
+[3]: https://github.com/googlesamples/android-DataLayer
 ]]>
         </intro>
     </metadata>
diff --git a/wearable/wear/AlwaysOn/Wearable/build.gradle b/wearable/wear/AlwaysOn/Wearable/build.gradle
index b3279cb..6a22d1c 100644
--- a/wearable/wear/AlwaysOn/Wearable/build.gradle
+++ b/wearable/wear/AlwaysOn/Wearable/build.gradle
@@ -2,10 +2,11 @@
 buildscript {
     repositories {
         jcenter()
+        google()
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.1'
     }
 }
 
@@ -13,16 +14,22 @@
 
 repositories {
     jcenter()
-    maven {
-        url 'https://maven.google.com'
-    }
+    google()
 }
 
 
 
 dependencies {
 
-    compile 'com.android.support:wear:27.0.0'
+    compile 'com.android.support:wear:27.1.0'
+
+
+    compile 'com.google.android.gms:play-services-wearable:11.8.0'
+    compile 'com.android.support:support-v13:27.1.0'
+
+    provided 'com.google.android.wearable:wearable:2.3.0'
+
+    compile 'com.google.android.support:wearable:2.3.0'
 
 }
 
@@ -36,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 26
+    compileSdkVersion 26
 
-    buildToolsVersion "26.0.1"
+    buildToolsVersion "27.0.3"
 
     defaultConfig {
         versionCode 1
diff --git a/wearable/wear/AlwaysOn/build.gradle b/wearable/wear/AlwaysOn/build.gradle
index 18f393f..df4616b 100644
--- a/wearable/wear/AlwaysOn/build.gradle
+++ b/wearable/wear/AlwaysOn/build.gradle
@@ -9,3 +9,9 @@
 }
 apply from: "../../../../../build/build.gradle"
 // END_EXCLUDE
+
+buildscript {
+    repositories {
+        google()
+    }
+}
\ No newline at end of file
diff --git a/wearable/wear/AlwaysOn/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/AlwaysOn/gradle/wrapper/gradle-wrapper.properties
index c2cde24..2ceef03 100644
--- a/wearable/wear/AlwaysOn/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/AlwaysOn/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/AlwaysOn/template-params.xml b/wearable/wear/AlwaysOn/template-params.xml
index 051a26e..eb743d8 100644
--- a/wearable/wear/AlwaysOn/template-params.xml
+++ b/wearable/wear/AlwaysOn/template-params.xml
@@ -24,12 +24,12 @@
     <targetSdkVersionWear>26</targetSdkVersionWear>
     <multiDexEnabled>true</multiDexEnabled>
 
-    <dependency_wearable>com.android.support:wear:27.0.0</dependency_wearable>
+    <dependency_wearable>com.android.support:wear:27.1.0</dependency_wearable>
 
     <strings>
         <intro>
             <![CDATA[
-            Demonstrates a native Android Wear app using ambient screen support.
+            Demonstrates a native Wear app using ambient screen support.
             ]]>>
         </intro>
     </strings>
@@ -58,7 +58,7 @@
         </api_refs>
         <description>
             <![CDATA[
-A basic sample showing how to support ambient mode for native Android Wear apps.
+A basic sample showing how to support ambient mode for native Wear apps.
 ]]>
         </description>
 
diff --git a/wearable/wear/DataLayer/Application/src/main/java/com/example/android/wearable/datalayer/MainActivity.java b/wearable/wear/DataLayer/Application/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
index ca86d7a..b7f9f8b 100644
--- a/wearable/wear/DataLayer/Application/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
+++ b/wearable/wear/DataLayer/Application/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
@@ -19,13 +19,13 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentSender;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.provider.MediaStore;
+import android.support.annotation.WorkerThread;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -36,23 +36,19 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
-import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
-import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.android.gms.tasks.Task;
+import com.google.android.gms.tasks.Tasks;
 import com.google.android.gms.wearable.Asset;
-import com.google.android.gms.wearable.CapabilityApi;
+import com.google.android.gms.wearable.CapabilityClient;
 import com.google.android.gms.wearable.CapabilityInfo;
-import com.google.android.gms.wearable.DataApi;
-import com.google.android.gms.wearable.DataApi.DataItemResult;
+import com.google.android.gms.wearable.DataClient;
 import com.google.android.gms.wearable.DataEvent;
 import com.google.android.gms.wearable.DataEventBuffer;
-import com.google.android.gms.wearable.MessageApi;
-import com.google.android.gms.wearable.MessageApi.SendMessageResult;
+import com.google.android.gms.wearable.DataItem;
+import com.google.android.gms.wearable.MessageClient;
 import com.google.android.gms.wearable.MessageEvent;
 import com.google.android.gms.wearable.Node;
-import com.google.android.gms.wearable.NodeApi;
 import com.google.android.gms.wearable.PutDataMapRequest;
 import com.google.android.gms.wearable.PutDataRequest;
 import com.google.android.gms.wearable.Wearable;
@@ -62,6 +58,8 @@
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -73,17 +71,12 @@
  * to the paired wearable.
  */
 public class MainActivity extends Activity implements
-        CapabilityApi.CapabilityListener,
-        MessageApi.MessageListener,
-        DataApi.DataListener,
-        ConnectionCallbacks,
-        OnConnectionFailedListener {
+        DataClient.OnDataChangedListener,
+        MessageClient.OnMessageReceivedListener,
+        CapabilityClient.OnCapabilityChangedListener {
 
     private static final String TAG = "MainActivity";
 
-    //Request code for launching the Intent to resolve Google Play services errors.
-    private static final int REQUEST_RESOLVE_ERROR = 1000;
-
     private static final int REQUEST_IMAGE_CAPTURE = 1;
 
     private static final String START_ACTIVITY_PATH = "/start-activity";
@@ -92,8 +85,6 @@
     private static final String IMAGE_KEY = "photo";
     private static final String COUNT_KEY = "count";
 
-    private GoogleApiClient mGoogleApiClient;
-    private boolean mResolvingError = false;
     private boolean mCameraSupported = false;
 
     private ListView mDataItemList;
@@ -112,6 +103,7 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         LOGD(TAG, "onCreate");
+
         mCameraSupported = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
         setContentView(R.layout.main_activity);
         setupViews();
@@ -121,20 +113,6 @@
         mDataItemList.setAdapter(mDataItemListAdapter);
 
         mGeneratorExecutor = new ScheduledThreadPoolExecutor(1);
-
-        mGoogleApiClient = new GoogleApiClient.Builder(this)
-                .addApi(Wearable.API)
-                .addConnectionCallbacks(this)
-                .addOnConnectionFailedListener(this)
-                .build();
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        if (!mResolvingError) {
-            mGoogleApiClient.connect();
-        }
     }
 
     @Override
@@ -142,23 +120,27 @@
         super.onResume();
         mDataItemGeneratorFuture = mGeneratorExecutor.scheduleWithFixedDelay(
                 new DataItemGenerator(), 1, 5, TimeUnit.SECONDS);
+
+        mStartActivityBtn.setEnabled(true);
+        mSendPhotoBtn.setEnabled(mCameraSupported);
+
+        // Instantiates clients without member variables, as clients are inexpensive to create and
+        // won't lose their listeners. (They are cached and shared between GoogleApi instances.)
+        Wearable.getDataClient(this).addListener(this);
+        Wearable.getMessageClient(this).addListener(this);
+        Wearable.getCapabilityClient(this)
+                .addListener(
+                        this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE);
     }
 
     @Override
     public void onPause() {
         super.onPause();
         mDataItemGeneratorFuture.cancel(true /* mayInterruptIfRunning */);
-    }
 
-    @Override
-    protected void onStop() {
-        if (!mResolvingError && (mGoogleApiClient != null) && (mGoogleApiClient.isConnected())) {
-            Wearable.DataApi.removeListener(mGoogleApiClient, this);
-            Wearable.MessageApi.removeListener(mGoogleApiClient, this);
-            Wearable.CapabilityApi.removeListener(mGoogleApiClient, this);
-            mGoogleApiClient.disconnect();
-        }
-        super.onStop();
+        Wearable.getDataClient(this).removeListener(this);
+        Wearable.getMessageClient(this).removeListener(this);
+        Wearable.getCapabilityClient(this).removeListener(this);
     }
 
     @Override
@@ -171,49 +153,6 @@
     }
 
     @Override
-    public void onConnected(Bundle connectionHint) {
-        LOGD(TAG, "Google API Client was connected");
-        mResolvingError = false;
-        mStartActivityBtn.setEnabled(true);
-        mSendPhotoBtn.setEnabled(mCameraSupported);
-        Wearable.DataApi.addListener(mGoogleApiClient, this);
-        Wearable.MessageApi.addListener(mGoogleApiClient, this);
-        Wearable.CapabilityApi.addListener(
-                mGoogleApiClient, this, Uri.parse("wear://"), CapabilityApi.FILTER_REACHABLE);
-    }
-
-    @Override
-    public void onConnectionSuspended(int cause) {
-        LOGD(TAG, "Connection to Google API client was suspended");
-        mStartActivityBtn.setEnabled(false);
-        mSendPhotoBtn.setEnabled(false);
-    }
-
-    @Override
-    public void onConnectionFailed(ConnectionResult result) {
-        if (!mResolvingError) {
-
-            if (result.hasResolution()) {
-                try {
-                    mResolvingError = true;
-                    result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
-                } catch (IntentSender.SendIntentException e) {
-                    // There was an error with the resolution intent. Try again.
-                    mGoogleApiClient.connect();
-                }
-            } else {
-                Log.e(TAG, "Connection to Google API client has failed");
-                mResolvingError = false;
-                mStartActivityBtn.setEnabled(false);
-                mSendPhotoBtn.setEnabled(false);
-                Wearable.DataApi.removeListener(mGoogleApiClient, this);
-                Wearable.MessageApi.removeListener(mGoogleApiClient, this);
-                Wearable.CapabilityApi.removeListener(mGoogleApiClient, this);
-            }
-        }
-    }
-
-    @Override
     public void onDataChanged(DataEventBuffer dataEvents) {
         LOGD(TAG, "onDataChanged: " + dataEvents);
 
@@ -258,7 +197,7 @@
     }
 
     public void onSendPhotoClick(View view) {
-        if (null != mImageBitmap && mGoogleApiClient.isConnected()) {
+        if (null != mImageBitmap) {
             sendPhoto(toAsset(mImageBitmap));
         }
     }
@@ -274,19 +213,24 @@
         new StartWearableActivityTask().execute();
     }
 
+    @WorkerThread
     private void sendStartActivityMessage(String node) {
-        Wearable.MessageApi.sendMessage(
-                mGoogleApiClient, node, START_ACTIVITY_PATH, new byte[0]).setResultCallback(
-                new ResultCallback<SendMessageResult>() {
-                    @Override
-                    public void onResult(SendMessageResult sendMessageResult) {
-                        if (!sendMessageResult.getStatus().isSuccess()) {
-                            Log.e(TAG, "Failed to send message with status code: "
-                                    + sendMessageResult.getStatus().getStatusCode());
-                        }
-                    }
-                }
-        );
+
+        Task<Integer> sendMessageTask =
+                Wearable.getMessageClient(this).sendMessage(node, START_ACTIVITY_PATH, new byte[0]);
+
+        try {
+            // Block on a task and get the result synchronously (because this is on a background
+            // thread).
+            Integer result = Tasks.await(sendMessageTask);
+            LOGD(TAG, "Message sent: " + result);
+
+        } catch (ExecutionException exception) {
+            Log.e(TAG, "Task failed: " + exception);
+
+        } catch (InterruptedException exception) {
+            Log.e(TAG, "Interrupt occurred: " + exception);
+        }
     }
 
     /**
@@ -333,23 +277,38 @@
         PutDataRequest request = dataMap.asPutDataRequest();
         request.setUrgent();
 
-        Wearable.DataApi.putDataItem(mGoogleApiClient, request)
-                .setResultCallback(new ResultCallback<DataItemResult>() {
-                    @Override
-                    public void onResult(DataItemResult dataItemResult) {
-                        LOGD(TAG, "Sending image was successful: " + dataItemResult.getStatus()
-                                .isSuccess());
-                    }
-                });
+        Task<DataItem> dataItemTask = Wearable.getDataClient(this).putDataItem(request);
+
+        dataItemTask.addOnSuccessListener(new OnSuccessListener<DataItem>() {
+            @Override
+            public void onSuccess(DataItem dataItem) {
+                LOGD(TAG, "Sending image was successful: " + dataItem);
+            }
+        });
     }
 
+    @WorkerThread
     private Collection<String> getNodes() {
         HashSet<String> results = new HashSet<>();
-        NodeApi.GetConnectedNodesResult nodes =
-                Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
 
-        for (Node node : nodes.getNodes()) {
-            results.add(node.getId());
+        Task<List<Node>> nodeListTask =
+                Wearable.getNodeClient(getApplicationContext()).getConnectedNodes();
+
+        try {
+            // Block on a task and get the result synchronously (because this is on a background
+            // thread).
+            List<Node> nodes = Tasks.await(nodeListTask);
+
+            for (Node node : nodes) {
+                results.add(node.getId());
+
+            }
+
+        } catch (ExecutionException exception) {
+            Log.e(TAG, "Task failed: " + exception);
+
+        } catch (InterruptedException exception) {
+            Log.e(TAG, "Interrupt occurred: " + exception);
         }
 
         return results;
@@ -441,19 +400,23 @@
             request.setUrgent();
 
             LOGD(TAG, "Generating DataItem: " + request);
-            if (!mGoogleApiClient.isConnected()) {
-                return;
+
+            Task<DataItem> dataItemTask =
+                    Wearable.getDataClient(getApplicationContext()).putDataItem(request);
+
+            try {
+                // Block on a task and get the result synchronously (because this is on a background
+                // thread).
+                DataItem dataItem = Tasks.await(dataItemTask);
+
+                LOGD(TAG, "DataItem saved: " + dataItem);
+
+            } catch (ExecutionException exception) {
+                Log.e(TAG, "Task failed: " + exception);
+
+            } catch (InterruptedException exception) {
+                Log.e(TAG, "Interrupt occurred: " + exception);
             }
-            Wearable.DataApi.putDataItem(mGoogleApiClient, request)
-                    .setResultCallback(new ResultCallback<DataItemResult>() {
-                        @Override
-                        public void onResult(DataItemResult dataItemResult) {
-                            if (!dataItemResult.getStatus().isSuccess()) {
-                                Log.e(TAG, "ERROR: failed to putDataItem, status code: "
-                                        + dataItemResult.getStatus().getStatusCode());
-                            }
-                        }
-                    });
         }
     }
 }
\ No newline at end of file
diff --git a/wearable/wear/DataLayer/LICENSE b/wearable/wear/DataLayer/LICENSE
index 4f22946..d5cf8f3 100644
--- a/wearable/wear/DataLayer/LICENSE
+++ b/wearable/wear/DataLayer/LICENSE
@@ -201,447 +201,3 @@
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-
-All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav 
-and *.ogg) are licensed under the CC-BY-NC license. All other files are 
-licensed under the Apache 2 license.
-
-CC-BY-NC License
-----------------
-
-Attribution-NonCommercial-ShareAlike 4.0 International
-
-=======================================================================
-
-Creative Commons Corporation ("Creative Commons") is not a law firm and
-does not provide legal services or legal advice. Distribution of
-Creative Commons public licenses does not create a lawyer-client or
-other relationship. Creative Commons makes its licenses and related
-information available on an "as-is" basis. Creative Commons gives no
-warranties regarding its licenses, any material licensed under their
-terms and conditions, or any related information. Creative Commons
-disclaims all liability for damages resulting from their use to the
-fullest extent possible.
-
-Using Creative Commons Public Licenses
-
-Creative Commons public licenses provide a standard set of terms and
-conditions that creators and other rights holders may use to share
-original works of authorship and other material subject to copyright
-and certain other rights specified in the public license below. The
-following considerations are for informational purposes only, are not
-exhaustive, and do not form part of our licenses.
-
-     Considerations for licensors: Our public licenses are
-     intended for use by those authorized to give the public
-     permission to use material in ways otherwise restricted by
-     copyright and certain other rights. Our licenses are
-     irrevocable. Licensors should read and understand the terms
-     and conditions of the license they choose before applying it.
-     Licensors should also secure all rights necessary before
-     applying our licenses so that the public can reuse the
-     material as expected. Licensors should clearly mark any
-     material not subject to the license. This includes other CC-
-     licensed material, or material used under an exception or
-     limitation to copyright. More considerations for licensors:
-	wiki.creativecommons.org/Considerations_for_licensors
-
-     Considerations for the public: By using one of our public
-     licenses, a licensor grants the public permission to use the
-     licensed material under specified terms and conditions. If
-     the licensor's permission is not necessary for any reason--for
-     example, because of any applicable exception or limitation to
-     copyright--then that use is not regulated by the license. Our
-     licenses grant only permissions under copyright and certain
-     other rights that a licensor has authority to grant. Use of
-     the licensed material may still be restricted for other
-     reasons, including because others have copyright or other
-     rights in the material. A licensor may make special requests,
-     such as asking that all changes be marked or described.
-     Although not required by our licenses, you are encouraged to
-     respect those requests where reasonable. More_considerations
-     for the public: 
-	wiki.creativecommons.org/Considerations_for_licensees
-
-=======================================================================
-
-Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
-Public License
-
-By exercising the Licensed Rights (defined below), You accept and agree
-to be bound by the terms and conditions of this Creative Commons
-Attribution-NonCommercial-ShareAlike 4.0 International Public License
-("Public License"). To the extent this Public License may be
-interpreted as a contract, You are granted the Licensed Rights in
-consideration of Your acceptance of these terms and conditions, and the
-Licensor grants You such rights in consideration of benefits the
-Licensor receives from making the Licensed Material available under
-these terms and conditions.
-
-
-Section 1 -- Definitions.
-
-  a. Adapted Material means material subject to Copyright and Similar
-     Rights that is derived from or based upon the Licensed Material
-     and in which the Licensed Material is translated, altered,
-     arranged, transformed, or otherwise modified in a manner requiring
-     permission under the Copyright and Similar Rights held by the
-     Licensor. For purposes of this Public License, where the Licensed
-     Material is a musical work, performance, or sound recording,
-     Adapted Material is always produced where the Licensed Material is
-     synched in timed relation with a moving image.
-
-  b. Adapter's License means the license You apply to Your Copyright
-     and Similar Rights in Your contributions to Adapted Material in
-     accordance with the terms and conditions of this Public License.
-
-  c. BY-NC-SA Compatible License means a license listed at
-     creativecommons.org/compatiblelicenses, approved by Creative
-     Commons as essentially the equivalent of this Public License.
-
-  d. Copyright and Similar Rights means copyright and/or similar rights
-     closely related to copyright including, without limitation,
-     performance, broadcast, sound recording, and Sui Generis Database
-     Rights, without regard to how the rights are labeled or
-     categorized. For purposes of this Public License, the rights
-     specified in Section 2(b)(1)-(2) are not Copyright and Similar
-     Rights.
-
-  e. Effective Technological Measures means those measures that, in the
-     absence of proper authority, may not be circumvented under laws
-     fulfilling obligations under Article 11 of the WIPO Copyright
-     Treaty adopted on December 20, 1996, and/or similar international
-     agreements.
-
-  f. Exceptions and Limitations means fair use, fair dealing, and/or
-     any other exception or limitation to Copyright and Similar Rights
-     that applies to Your use of the Licensed Material.
-
-  g. License Elements means the license attributes listed in the name
-     of a Creative Commons Public License. The License Elements of this
-     Public License are Attribution, NonCommercial, and ShareAlike.
-
-  h. Licensed Material means the artistic or literary work, database,
-     or other material to which the Licensor applied this Public
-     License.
-
-  i. Licensed Rights means the rights granted to You subject to the
-     terms and conditions of this Public License, which are limited to
-     all Copyright and Similar Rights that apply to Your use of the
-     Licensed Material and that the Licensor has authority to license.
-
-  j. Licensor means the individual(s) or entity(ies) granting rights
-     under this Public License.
-
-  k. NonCommercial means not primarily intended for or directed towards
-     commercial advantage or monetary compensation. For purposes of
-     this Public License, the exchange of the Licensed Material for
-     other material subject to Copyright and Similar Rights by digital
-     file-sharing or similar means is NonCommercial provided there is
-     no payment of monetary compensation in connection with the
-     exchange.
-
-  l. Share means to provide material to the public by any means or
-     process that requires permission under the Licensed Rights, such
-     as reproduction, public display, public performance, distribution,
-     dissemination, communication, or importation, and to make material
-     available to the public including in ways that members of the
-     public may access the material from a place and at a time
-     individually chosen by them.
-
-  m. Sui Generis Database Rights means rights other than copyright
-     resulting from Directive 96/9/EC of the European Parliament and of
-     the Council of 11 March 1996 on the legal protection of databases,
-     as amended and/or succeeded, as well as other essentially
-     equivalent rights anywhere in the world.
-
-  n. You means the individual or entity exercising the Licensed Rights
-     under this Public License. Your has a corresponding meaning.
-
-
-Section 2 -- Scope.
-
-  a. License grant.
-
-       1. Subject to the terms and conditions of this Public License,
-          the Licensor hereby grants You a worldwide, royalty-free,
-          non-sublicensable, non-exclusive, irrevocable license to
-          exercise the Licensed Rights in the Licensed Material to:
-
-            a. reproduce and Share the Licensed Material, in whole or
-               in part, for NonCommercial purposes only; and
-
-            b. produce, reproduce, and Share Adapted Material for
-               NonCommercial purposes only.
-
-       2. Exceptions and Limitations. For the avoidance of doubt, where
-          Exceptions and Limitations apply to Your use, this Public
-          License does not apply, and You do not need to comply with
-          its terms and conditions.
-
-       3. Term. The term of this Public License is specified in Section
-          6(a).
-
-       4. Media and formats; technical modifications allowed. The
-          Licensor authorizes You to exercise the Licensed Rights in
-          all media and formats whether now known or hereafter created,
-          and to make technical modifications necessary to do so. The
-          Licensor waives and/or agrees not to assert any right or
-          authority to forbid You from making technical modifications
-          necessary to exercise the Licensed Rights, including
-          technical modifications necessary to circumvent Effective
-          Technological Measures. For purposes of this Public License,
-          simply making modifications authorized by this Section 2(a)
-          (4) never produces Adapted Material.
-
-       5. Downstream recipients.
-
-            a. Offer from the Licensor -- Licensed Material. Every
-               recipient of the Licensed Material automatically
-               receives an offer from the Licensor to exercise the
-               Licensed Rights under the terms and conditions of this
-               Public License.
-
-            b. Additional offer from the Licensor -- Adapted Material.
-               Every recipient of Adapted Material from You
-               automatically receives an offer from the Licensor to
-               exercise the Licensed Rights in the Adapted Material
-               under the conditions of the Adapter's License You apply.
-
-            c. No downstream restrictions. You may not offer or impose
-               any additional or different terms or conditions on, or
-               apply any Effective Technological Measures to, the
-               Licensed Material if doing so restricts exercise of the
-               Licensed Rights by any recipient of the Licensed
-               Material.
-
-       6. No endorsement. Nothing in this Public License constitutes or
-          may be construed as permission to assert or imply that You
-          are, or that Your use of the Licensed Material is, connected
-          with, or sponsored, endorsed, or granted official status by,
-          the Licensor or others designated to receive attribution as
-          provided in Section 3(a)(1)(A)(i).
-
-  b. Other rights.
-
-       1. Moral rights, such as the right of integrity, are not
-          licensed under this Public License, nor are publicity,
-          privacy, and/or other similar personality rights; however, to
-          the extent possible, the Licensor waives and/or agrees not to
-          assert any such rights held by the Licensor to the limited
-          extent necessary to allow You to exercise the Licensed
-          Rights, but not otherwise.
-
-       2. Patent and trademark rights are not licensed under this
-          Public License.
-
-       3. To the extent possible, the Licensor waives any right to
-          collect royalties from You for the exercise of the Licensed
-          Rights, whether directly or through a collecting society
-          under any voluntary or waivable statutory or compulsory
-          licensing scheme. In all other cases the Licensor expressly
-          reserves any right to collect such royalties, including when
-          the Licensed Material is used other than for NonCommercial
-          purposes.
-
-
-Section 3 -- License Conditions.
-
-Your exercise of the Licensed Rights is expressly made subject to the
-following conditions.
-
-  a. Attribution.
-
-       1. If You Share the Licensed Material (including in modified
-          form), You must:
-
-            a. retain the following if it is supplied by the Licensor
-               with the Licensed Material:
-
-                 i. identification of the creator(s) of the Licensed
-                    Material and any others designated to receive
-                    attribution, in any reasonable manner requested by
-                    the Licensor (including by pseudonym if
-                    designated);
-
-                ii. a copyright notice;
-
-               iii. a notice that refers to this Public License;
-
-                iv. a notice that refers to the disclaimer of
-                    warranties;
-
-                 v. a URI or hyperlink to the Licensed Material to the
-                    extent reasonably practicable;
-
-            b. indicate if You modified the Licensed Material and
-               retain an indication of any previous modifications; and
-
-            c. indicate the Licensed Material is licensed under this
-               Public License, and include the text of, or the URI or
-               hyperlink to, this Public License.
-
-       2. You may satisfy the conditions in Section 3(a)(1) in any
-          reasonable manner based on the medium, means, and context in
-          which You Share the Licensed Material. For example, it may be
-          reasonable to satisfy the conditions by providing a URI or
-          hyperlink to a resource that includes the required
-          information.
-       3. If requested by the Licensor, You must remove any of the
-          information required by Section 3(a)(1)(A) to the extent
-          reasonably practicable.
-
-  b. ShareAlike.
-
-     In addition to the conditions in Section 3(a), if You Share
-     Adapted Material You produce, the following conditions also apply.
-
-       1. The Adapter's License You apply must be a Creative Commons
-          license with the same License Elements, this version or
-          later, or a BY-NC-SA Compatible License.
-
-       2. You must include the text of, or the URI or hyperlink to, the
-          Adapter's License You apply. You may satisfy this condition
-          in any reasonable manner based on the medium, means, and
-          context in which You Share Adapted Material.
-
-       3. You may not offer or impose any additional or different terms
-          or conditions on, or apply any Effective Technological
-          Measures to, Adapted Material that restrict exercise of the
-          rights granted under the Adapter's License You apply.
-
-
-Section 4 -- Sui Generis Database Rights.
-
-Where the Licensed Rights include Sui Generis Database Rights that
-apply to Your use of the Licensed Material:
-
-  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
-     to extract, reuse, reproduce, and Share all or a substantial
-     portion of the contents of the database for NonCommercial purposes
-     only;
-
-  b. if You include all or a substantial portion of the database
-     contents in a database in which You have Sui Generis Database
-     Rights, then the database in which You have Sui Generis Database
-     Rights (but not its individual contents) is Adapted Material,
-     including for purposes of Section 3(b); and
-
-  c. You must comply with the conditions in Section 3(a) if You Share
-     all or a substantial portion of the contents of the database.
-
-For the avoidance of doubt, this Section 4 supplements and does not
-replace Your obligations under this Public License where the Licensed
-Rights include other Copyright and Similar Rights.
-
-
-Section 5 -- Disclaimer of Warranties and Limitation of Liability.
-
-  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
-     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
-     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
-     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
-     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
-     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
-     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
-     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
-     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
-     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
-
-  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
-     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
-     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
-     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
-     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
-     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
-     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
-     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
-     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
-
-  c. The disclaimer of warranties and limitation of liability provided
-     above shall be interpreted in a manner that, to the extent
-     possible, most closely approximates an absolute disclaimer and
-     waiver of all liability.
-
-
-Section 6 -- Term and Termination.
-
-  a. This Public License applies for the term of the Copyright and
-     Similar Rights licensed here. However, if You fail to comply with
-     this Public License, then Your rights under this Public License
-     terminate automatically.
-
-  b. Where Your right to use the Licensed Material has terminated under
-     Section 6(a), it reinstates:
-
-       1. automatically as of the date the violation is cured, provided
-          it is cured within 30 days of Your discovery of the
-          violation; or
-
-       2. upon express reinstatement by the Licensor.
-
-     For the avoidance of doubt, this Section 6(b) does not affect any
-     right the Licensor may have to seek remedies for Your violations
-     of this Public License.
-
-  c. For the avoidance of doubt, the Licensor may also offer the
-     Licensed Material under separate terms or conditions or stop
-     distributing the Licensed Material at any time; however, doing so
-     will not terminate this Public License.
-
-  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
-     License.
-
-
-Section 7 -- Other Terms and Conditions.
-
-  a. The Licensor shall not be bound by any additional or different
-     terms or conditions communicated by You unless expressly agreed.
-
-  b. Any arrangements, understandings, or agreements regarding the
-     Licensed Material not stated herein are separate from and
-     independent of the terms and conditions of this Public License.
-
-
-Section 8 -- Interpretation.
-
-  a. For the avoidance of doubt, this Public License does not, and
-     shall not be interpreted to, reduce, limit, restrict, or impose
-     conditions on any use of the Licensed Material that could lawfully
-     be made without permission under this Public License.
-
-  b. To the extent possible, if any provision of this Public License is
-     deemed unenforceable, it shall be automatically reformed to the
-     minimum extent necessary to make it enforceable. If the provision
-     cannot be reformed, it shall be severed from this Public License
-     without affecting the enforceability of the remaining terms and
-     conditions.
-
-  c. No term or condition of this Public License will be waived and no
-     failure to comply consented to unless expressly agreed to by the
-     Licensor.
-
-  d. Nothing in this Public License constitutes or may be interpreted
-     as a limitation upon, or waiver of, any privileges and immunities
-     that apply to the Licensor or You, including from the legal
-     processes of any jurisdiction or authority.
-
-=======================================================================
-
-Creative Commons is not a party to its public licenses.
-Notwithstanding, Creative Commons may elect to apply one of its public
-licenses to material it publishes and in those instances will be
-considered the "Licensor." Except for the limited purpose of indicating
-that material is shared under a Creative Commons public license or as
-otherwise permitted by the Creative Commons policies published at
-creativecommons.org/policies, Creative Commons does not authorize the
-use of the trademark "Creative Commons" or any other trademark or logo
-of Creative Commons without its prior written consent including,
-without limitation, in connection with any unauthorized modifications
-to any of its public licenses or any other arrangements,
-understandings, or agreements concerning use of licensed material. For
-the avoidance of doubt, this paragraph does not form part of the public
-licenses.
-
-Creative Commons may be contacted at creativecommons.org.
-
diff --git a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/MainActivity.java b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
index 402912f..feec09c 100644
--- a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
+++ b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
@@ -38,20 +38,17 @@
 import com.example.android.wearable.datalayer.fragments.AssetFragment;
 import com.example.android.wearable.datalayer.fragments.DataFragment;
 import com.example.android.wearable.datalayer.fragments.DiscoveryFragment;
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
-import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
-import com.google.android.gms.common.api.PendingResult;
-import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.android.gms.tasks.Task;
+import com.google.android.gms.tasks.Tasks;
 import com.google.android.gms.wearable.Asset;
-import com.google.android.gms.wearable.CapabilityApi;
+import com.google.android.gms.wearable.CapabilityClient;
 import com.google.android.gms.wearable.CapabilityInfo;
-import com.google.android.gms.wearable.DataApi;
+import com.google.android.gms.wearable.DataClient;
 import com.google.android.gms.wearable.DataEvent;
 import com.google.android.gms.wearable.DataEventBuffer;
 import com.google.android.gms.wearable.DataMapItem;
-import com.google.android.gms.wearable.MessageApi;
+import com.google.android.gms.wearable.MessageClient;
 import com.google.android.gms.wearable.MessageEvent;
 import com.google.android.gms.wearable.Node;
 import com.google.android.gms.wearable.Wearable;
@@ -62,6 +59,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
 
 /**
  * The main activity with a view pager, containing three pages:<p/>
@@ -78,17 +76,14 @@
  * </ul>
  */
 public class MainActivity extends Activity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        DataApi.DataListener,
-        MessageApi.MessageListener,
-        CapabilityApi.CapabilityListener {
+        DataClient.OnDataChangedListener,
+        MessageClient.OnMessageReceivedListener,
+        CapabilityClient.OnCapabilityChangedListener {
 
     private static final String TAG = "MainActivity";
     private static final String CAPABILITY_1_NAME = "capability_1";
     private static final String CAPABILITY_2_NAME = "capability_2";
 
-    private GoogleApiClient mGoogleApiClient;
     private GridViewPager mPager;
     private DataFragment mDataFragment;
     private AssetFragment mAssetFragment;
@@ -99,48 +94,28 @@
         setContentView(R.layout.main_activity);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
         setupViews();
-        mGoogleApiClient = new GoogleApiClient.Builder(this)
-                .addApi(Wearable.API)
-                .addConnectionCallbacks(this)
-                .addOnConnectionFailedListener(this)
-                .build();
     }
 
     @Override
     protected void onResume() {
         super.onResume();
-        mGoogleApiClient.connect();
+
+        // Instantiates clients without member variables, as clients are inexpensive to create and
+        // won't lose their listeners. (They are cached and shared between GoogleApi instances.)
+        Wearable.getDataClient(this).addListener(this);
+        Wearable.getMessageClient(this).addListener(this);
+        Wearable.getCapabilityClient(this)
+                .addListener(
+                        this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE);
     }
 
     @Override
     protected void onPause() {
-        if ((mGoogleApiClient != null) && mGoogleApiClient.isConnected()) {
-            Wearable.DataApi.removeListener(mGoogleApiClient, this);
-            Wearable.MessageApi.removeListener(mGoogleApiClient, this);
-            Wearable.CapabilityApi.removeListener(mGoogleApiClient, this);
-            mGoogleApiClient.disconnect();
-        }
-
         super.onPause();
-    }
 
-    @Override
-    public void onConnected(Bundle connectionHint) {
-        LOGD(TAG, "onConnected(): Successfully connected to Google API client");
-        Wearable.DataApi.addListener(mGoogleApiClient, this);
-        Wearable.MessageApi.addListener(mGoogleApiClient, this);
-        Wearable.CapabilityApi.addListener(
-                mGoogleApiClient, this, Uri.parse("wear://"), CapabilityApi.FILTER_REACHABLE);
-    }
-
-    @Override
-    public void onConnectionSuspended(int cause) {
-        LOGD(TAG, "onConnectionSuspended(): Connection to Google API client was suspended");
-    }
-
-    @Override
-    public void onConnectionFailed(ConnectionResult result) {
-        Log.e(TAG, "onConnectionFailed(): Failed to connect, with result: " + result);
+        Wearable.getDataClient(this).removeListener(this);
+        Wearable.getMessageClient(this).removeListener(this);
+        Wearable.getCapabilityClient(this).removeListener(this);
     }
 
     @Override
@@ -185,64 +160,6 @@
         }
     }
 
-    /**
-     * Find the connected nodes that provide at least one of the given capabilities
-     */
-    private void showNodes(final String... capabilityNames) {
-
-        PendingResult<CapabilityApi.GetAllCapabilitiesResult> pendingCapabilityResult =
-                Wearable.CapabilityApi.getAllCapabilities(
-                        mGoogleApiClient,
-                        CapabilityApi.FILTER_REACHABLE);
-
-        pendingCapabilityResult.setResultCallback(
-                new ResultCallback<CapabilityApi.GetAllCapabilitiesResult>() {
-                    @Override
-                    public void onResult(
-                            CapabilityApi.GetAllCapabilitiesResult getAllCapabilitiesResult) {
-
-                        if (!getAllCapabilitiesResult.getStatus().isSuccess()) {
-                            Log.e(TAG, "Failed to get capabilities");
-                            return;
-                        }
-
-                        Map<String, CapabilityInfo> capabilitiesMap =
-                                getAllCapabilitiesResult.getAllCapabilities();
-                        Set<Node> nodes = new HashSet<>();
-
-                        if (capabilitiesMap.isEmpty()) {
-                            showDiscoveredNodes(nodes);
-                            return;
-                        }
-                        for (String capabilityName : capabilityNames) {
-                            CapabilityInfo capabilityInfo = capabilitiesMap.get(capabilityName);
-                            if (capabilityInfo != null) {
-                                nodes.addAll(capabilityInfo.getNodes());
-                            }
-                        }
-                        showDiscoveredNodes(nodes);
-                    }
-
-                    private void showDiscoveredNodes(Set<Node> nodes) {
-                        List<String> nodesList = new ArrayList<>();
-                        for (Node node : nodes) {
-                            nodesList.add(node.getDisplayName());
-                        }
-                        LOGD(TAG, "Connected Nodes: " + (nodesList.isEmpty()
-                                ? "No connected device was found for the given capabilities"
-                                : TextUtils.join(",", nodesList)));
-                        String msg;
-                        if (!nodesList.isEmpty()) {
-                            msg = getString(R.string.connected_nodes,
-                                    TextUtils.join(", ", nodesList));
-                        } else {
-                            msg = getString(R.string.no_device);
-                        }
-                        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
-                    }
-                });
-    }
-
     @Override
     public void onMessageReceived(MessageEvent event) {
         LOGD(TAG, "onMessageReceived: " + event);
@@ -255,6 +172,53 @@
         mDataFragment.appendItem("onCapabilityChanged", capabilityInfo.toString());
     }
 
+    /**
+     * Find the connected nodes that provide at least one of the given capabilities
+     */
+    private void showNodes(final String... capabilityNames) {
+
+        Task<Map<String, CapabilityInfo>> capabilitiesTask =
+                Wearable.getCapabilityClient(this)
+                        .getAllCapabilities(CapabilityClient.FILTER_REACHABLE);
+
+        capabilitiesTask.addOnSuccessListener(new OnSuccessListener<Map<String, CapabilityInfo>>() {
+            @Override
+            public void onSuccess(Map<String, CapabilityInfo> capabilityInfoMap) {
+                Set<Node> nodes = new HashSet<>();
+
+                if (capabilityInfoMap.isEmpty()) {
+                    showDiscoveredNodes(nodes);
+                    return;
+                }
+                for (String capabilityName : capabilityNames) {
+                    CapabilityInfo capabilityInfo = capabilityInfoMap.get(capabilityName);
+                    if (capabilityInfo != null) {
+                        nodes.addAll(capabilityInfo.getNodes());
+                    }
+                }
+                showDiscoveredNodes(nodes);
+            }
+        });
+    }
+
+    private void showDiscoveredNodes(Set<Node> nodes) {
+        List<String> nodesList = new ArrayList<>();
+        for (Node node : nodes) {
+            nodesList.add(node.getDisplayName());
+        }
+        LOGD(TAG, "Connected Nodes: " + (nodesList.isEmpty()
+                ? "No connected device was found for the given capabilities"
+                : TextUtils.join(",", nodesList)));
+        String msg;
+        if (!nodesList.isEmpty()) {
+            msg = getString(R.string.connected_nodes,
+                    TextUtils.join(", ", nodesList));
+        } else {
+            msg = getString(R.string.no_device);
+        }
+        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
+    }
+
     private void setupViews() {
         mPager = (GridViewPager) findViewById(R.id.pager);
         mPager.setOffscreenPageCount(2);
@@ -318,14 +282,35 @@
 
                 Asset asset = params[0];
 
-                InputStream assetInputStream = Wearable.DataApi.getFdForAsset(
-                        mGoogleApiClient, asset).await().getInputStream();
+                Task<DataClient.GetFdForAssetResponse> getFdForAssetResponseTask =
+                        Wearable.getDataClient(getApplicationContext()).getFdForAsset(asset);
 
-                if (assetInputStream == null) {
-                    Log.w(TAG, "Requested an unknown Asset.");
+                try {
+                    // Block on a task and get the result synchronously. This is generally done
+                    // when executing a task inside a separately managed background thread. Doing
+                    // this on the main (UI) thread can cause your application to become
+                    // unresponsive.
+                    DataClient.GetFdForAssetResponse getFdForAssetResponse =
+                            Tasks.await(getFdForAssetResponseTask);
+
+                    InputStream assetInputStream = getFdForAssetResponse.getInputStream();
+
+                    if (assetInputStream != null) {
+                        return BitmapFactory.decodeStream(assetInputStream);
+
+                    } else {
+                        Log.w(TAG, "Requested an unknown Asset.");
+                        return null;
+                    }
+
+                } catch (ExecutionException exception) {
+                    Log.e(TAG, "Failed retrieving asset, Task failed: " + exception);
+                    return null;
+
+                } catch (InterruptedException exception) {
+                    Log.e(TAG, "Failed retrieving asset, interrupt occurred: " + exception);
                     return null;
                 }
-                return BitmapFactory.decodeStream(assetInputStream);
 
             } else {
                 Log.e(TAG, "Asset must be non-null");
diff --git a/wearable/wear/DataLayer/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/DataLayer/gradle/wrapper/gradle-wrapper.properties
index f6f95d8..0762007 100644
--- a/wearable/wear/DataLayer/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/DataLayer/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Apr 12 16:28:18 PDT 2016
+#Mon Nov 20 15:43:26 PST 2017
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/wearable/wear/DataLayer/template-params.xml b/wearable/wear/DataLayer/template-params.xml
index beeb26a..1f83906 100644
--- a/wearable/wear/DataLayer/template-params.xml
+++ b/wearable/wear/DataLayer/template-params.xml
@@ -20,8 +20,11 @@
     <package>com.example.android.wearable.datalayer</package>
 
     <minSdk>18</minSdk>
-    <targetSdkVersion>25</targetSdkVersion>
-    <targetSdkVersionWear>25</targetSdkVersionWear>
+    <targetSdkVersion>27</targetSdkVersion>
+    <compileSdkVersionWear>26</compileSdkVersionWear>
+    <targetSdkVersionWear>26</targetSdkVersionWear>
+
+    <multiDexEnabled>true</multiDexEnabled>
 
     <wearable>
         <has_handheld_app>true</has_handheld_app>
@@ -63,7 +66,7 @@
         </description>
         <intro>
 <![CDATA[
-This sample demonstrates how to make a handheld and an Android Wear device communicate
+This sample demonstrates how to make a handheld and an Wear device communicate
 using the [DataApi][2].
 It does this by sending a picture between connected devices.
 
diff --git a/wearable/wear/DelayedConfirmation/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/DelayedConfirmation/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/DelayedConfirmation/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/DelayedConfirmation/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/ElizaChat/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/ElizaChat/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/ElizaChat/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/ElizaChat/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/EmbeddedApp/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/EmbeddedApp/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/EmbeddedApp/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/EmbeddedApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/FindMyPhone/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/FindMyPhone/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/FindMyPhone/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/FindMyPhone/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/Flashlight/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/Flashlight/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/Flashlight/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/Flashlight/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/Geofencing/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/Geofencing/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/Geofencing/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/Geofencing/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/GridViewPager/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/GridViewPager/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/GridViewPager/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/GridViewPager/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/JumpingJack/LICENSE b/wearable/wear/JumpingJack/LICENSE
index 4f22946..d5cf8f3 100644
--- a/wearable/wear/JumpingJack/LICENSE
+++ b/wearable/wear/JumpingJack/LICENSE
@@ -201,447 +201,3 @@
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-
-All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav 
-and *.ogg) are licensed under the CC-BY-NC license. All other files are 
-licensed under the Apache 2 license.
-
-CC-BY-NC License
-----------------
-
-Attribution-NonCommercial-ShareAlike 4.0 International
-
-=======================================================================
-
-Creative Commons Corporation ("Creative Commons") is not a law firm and
-does not provide legal services or legal advice. Distribution of
-Creative Commons public licenses does not create a lawyer-client or
-other relationship. Creative Commons makes its licenses and related
-information available on an "as-is" basis. Creative Commons gives no
-warranties regarding its licenses, any material licensed under their
-terms and conditions, or any related information. Creative Commons
-disclaims all liability for damages resulting from their use to the
-fullest extent possible.
-
-Using Creative Commons Public Licenses
-
-Creative Commons public licenses provide a standard set of terms and
-conditions that creators and other rights holders may use to share
-original works of authorship and other material subject to copyright
-and certain other rights specified in the public license below. The
-following considerations are for informational purposes only, are not
-exhaustive, and do not form part of our licenses.
-
-     Considerations for licensors: Our public licenses are
-     intended for use by those authorized to give the public
-     permission to use material in ways otherwise restricted by
-     copyright and certain other rights. Our licenses are
-     irrevocable. Licensors should read and understand the terms
-     and conditions of the license they choose before applying it.
-     Licensors should also secure all rights necessary before
-     applying our licenses so that the public can reuse the
-     material as expected. Licensors should clearly mark any
-     material not subject to the license. This includes other CC-
-     licensed material, or material used under an exception or
-     limitation to copyright. More considerations for licensors:
-	wiki.creativecommons.org/Considerations_for_licensors
-
-     Considerations for the public: By using one of our public
-     licenses, a licensor grants the public permission to use the
-     licensed material under specified terms and conditions. If
-     the licensor's permission is not necessary for any reason--for
-     example, because of any applicable exception or limitation to
-     copyright--then that use is not regulated by the license. Our
-     licenses grant only permissions under copyright and certain
-     other rights that a licensor has authority to grant. Use of
-     the licensed material may still be restricted for other
-     reasons, including because others have copyright or other
-     rights in the material. A licensor may make special requests,
-     such as asking that all changes be marked or described.
-     Although not required by our licenses, you are encouraged to
-     respect those requests where reasonable. More_considerations
-     for the public: 
-	wiki.creativecommons.org/Considerations_for_licensees
-
-=======================================================================
-
-Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
-Public License
-
-By exercising the Licensed Rights (defined below), You accept and agree
-to be bound by the terms and conditions of this Creative Commons
-Attribution-NonCommercial-ShareAlike 4.0 International Public License
-("Public License"). To the extent this Public License may be
-interpreted as a contract, You are granted the Licensed Rights in
-consideration of Your acceptance of these terms and conditions, and the
-Licensor grants You such rights in consideration of benefits the
-Licensor receives from making the Licensed Material available under
-these terms and conditions.
-
-
-Section 1 -- Definitions.
-
-  a. Adapted Material means material subject to Copyright and Similar
-     Rights that is derived from or based upon the Licensed Material
-     and in which the Licensed Material is translated, altered,
-     arranged, transformed, or otherwise modified in a manner requiring
-     permission under the Copyright and Similar Rights held by the
-     Licensor. For purposes of this Public License, where the Licensed
-     Material is a musical work, performance, or sound recording,
-     Adapted Material is always produced where the Licensed Material is
-     synched in timed relation with a moving image.
-
-  b. Adapter's License means the license You apply to Your Copyright
-     and Similar Rights in Your contributions to Adapted Material in
-     accordance with the terms and conditions of this Public License.
-
-  c. BY-NC-SA Compatible License means a license listed at
-     creativecommons.org/compatiblelicenses, approved by Creative
-     Commons as essentially the equivalent of this Public License.
-
-  d. Copyright and Similar Rights means copyright and/or similar rights
-     closely related to copyright including, without limitation,
-     performance, broadcast, sound recording, and Sui Generis Database
-     Rights, without regard to how the rights are labeled or
-     categorized. For purposes of this Public License, the rights
-     specified in Section 2(b)(1)-(2) are not Copyright and Similar
-     Rights.
-
-  e. Effective Technological Measures means those measures that, in the
-     absence of proper authority, may not be circumvented under laws
-     fulfilling obligations under Article 11 of the WIPO Copyright
-     Treaty adopted on December 20, 1996, and/or similar international
-     agreements.
-
-  f. Exceptions and Limitations means fair use, fair dealing, and/or
-     any other exception or limitation to Copyright and Similar Rights
-     that applies to Your use of the Licensed Material.
-
-  g. License Elements means the license attributes listed in the name
-     of a Creative Commons Public License. The License Elements of this
-     Public License are Attribution, NonCommercial, and ShareAlike.
-
-  h. Licensed Material means the artistic or literary work, database,
-     or other material to which the Licensor applied this Public
-     License.
-
-  i. Licensed Rights means the rights granted to You subject to the
-     terms and conditions of this Public License, which are limited to
-     all Copyright and Similar Rights that apply to Your use of the
-     Licensed Material and that the Licensor has authority to license.
-
-  j. Licensor means the individual(s) or entity(ies) granting rights
-     under this Public License.
-
-  k. NonCommercial means not primarily intended for or directed towards
-     commercial advantage or monetary compensation. For purposes of
-     this Public License, the exchange of the Licensed Material for
-     other material subject to Copyright and Similar Rights by digital
-     file-sharing or similar means is NonCommercial provided there is
-     no payment of monetary compensation in connection with the
-     exchange.
-
-  l. Share means to provide material to the public by any means or
-     process that requires permission under the Licensed Rights, such
-     as reproduction, public display, public performance, distribution,
-     dissemination, communication, or importation, and to make material
-     available to the public including in ways that members of the
-     public may access the material from a place and at a time
-     individually chosen by them.
-
-  m. Sui Generis Database Rights means rights other than copyright
-     resulting from Directive 96/9/EC of the European Parliament and of
-     the Council of 11 March 1996 on the legal protection of databases,
-     as amended and/or succeeded, as well as other essentially
-     equivalent rights anywhere in the world.
-
-  n. You means the individual or entity exercising the Licensed Rights
-     under this Public License. Your has a corresponding meaning.
-
-
-Section 2 -- Scope.
-
-  a. License grant.
-
-       1. Subject to the terms and conditions of this Public License,
-          the Licensor hereby grants You a worldwide, royalty-free,
-          non-sublicensable, non-exclusive, irrevocable license to
-          exercise the Licensed Rights in the Licensed Material to:
-
-            a. reproduce and Share the Licensed Material, in whole or
-               in part, for NonCommercial purposes only; and
-
-            b. produce, reproduce, and Share Adapted Material for
-               NonCommercial purposes only.
-
-       2. Exceptions and Limitations. For the avoidance of doubt, where
-          Exceptions and Limitations apply to Your use, this Public
-          License does not apply, and You do not need to comply with
-          its terms and conditions.
-
-       3. Term. The term of this Public License is specified in Section
-          6(a).
-
-       4. Media and formats; technical modifications allowed. The
-          Licensor authorizes You to exercise the Licensed Rights in
-          all media and formats whether now known or hereafter created,
-          and to make technical modifications necessary to do so. The
-          Licensor waives and/or agrees not to assert any right or
-          authority to forbid You from making technical modifications
-          necessary to exercise the Licensed Rights, including
-          technical modifications necessary to circumvent Effective
-          Technological Measures. For purposes of this Public License,
-          simply making modifications authorized by this Section 2(a)
-          (4) never produces Adapted Material.
-
-       5. Downstream recipients.
-
-            a. Offer from the Licensor -- Licensed Material. Every
-               recipient of the Licensed Material automatically
-               receives an offer from the Licensor to exercise the
-               Licensed Rights under the terms and conditions of this
-               Public License.
-
-            b. Additional offer from the Licensor -- Adapted Material.
-               Every recipient of Adapted Material from You
-               automatically receives an offer from the Licensor to
-               exercise the Licensed Rights in the Adapted Material
-               under the conditions of the Adapter's License You apply.
-
-            c. No downstream restrictions. You may not offer or impose
-               any additional or different terms or conditions on, or
-               apply any Effective Technological Measures to, the
-               Licensed Material if doing so restricts exercise of the
-               Licensed Rights by any recipient of the Licensed
-               Material.
-
-       6. No endorsement. Nothing in this Public License constitutes or
-          may be construed as permission to assert or imply that You
-          are, or that Your use of the Licensed Material is, connected
-          with, or sponsored, endorsed, or granted official status by,
-          the Licensor or others designated to receive attribution as
-          provided in Section 3(a)(1)(A)(i).
-
-  b. Other rights.
-
-       1. Moral rights, such as the right of integrity, are not
-          licensed under this Public License, nor are publicity,
-          privacy, and/or other similar personality rights; however, to
-          the extent possible, the Licensor waives and/or agrees not to
-          assert any such rights held by the Licensor to the limited
-          extent necessary to allow You to exercise the Licensed
-          Rights, but not otherwise.
-
-       2. Patent and trademark rights are not licensed under this
-          Public License.
-
-       3. To the extent possible, the Licensor waives any right to
-          collect royalties from You for the exercise of the Licensed
-          Rights, whether directly or through a collecting society
-          under any voluntary or waivable statutory or compulsory
-          licensing scheme. In all other cases the Licensor expressly
-          reserves any right to collect such royalties, including when
-          the Licensed Material is used other than for NonCommercial
-          purposes.
-
-
-Section 3 -- License Conditions.
-
-Your exercise of the Licensed Rights is expressly made subject to the
-following conditions.
-
-  a. Attribution.
-
-       1. If You Share the Licensed Material (including in modified
-          form), You must:
-
-            a. retain the following if it is supplied by the Licensor
-               with the Licensed Material:
-
-                 i. identification of the creator(s) of the Licensed
-                    Material and any others designated to receive
-                    attribution, in any reasonable manner requested by
-                    the Licensor (including by pseudonym if
-                    designated);
-
-                ii. a copyright notice;
-
-               iii. a notice that refers to this Public License;
-
-                iv. a notice that refers to the disclaimer of
-                    warranties;
-
-                 v. a URI or hyperlink to the Licensed Material to the
-                    extent reasonably practicable;
-
-            b. indicate if You modified the Licensed Material and
-               retain an indication of any previous modifications; and
-
-            c. indicate the Licensed Material is licensed under this
-               Public License, and include the text of, or the URI or
-               hyperlink to, this Public License.
-
-       2. You may satisfy the conditions in Section 3(a)(1) in any
-          reasonable manner based on the medium, means, and context in
-          which You Share the Licensed Material. For example, it may be
-          reasonable to satisfy the conditions by providing a URI or
-          hyperlink to a resource that includes the required
-          information.
-       3. If requested by the Licensor, You must remove any of the
-          information required by Section 3(a)(1)(A) to the extent
-          reasonably practicable.
-
-  b. ShareAlike.
-
-     In addition to the conditions in Section 3(a), if You Share
-     Adapted Material You produce, the following conditions also apply.
-
-       1. The Adapter's License You apply must be a Creative Commons
-          license with the same License Elements, this version or
-          later, or a BY-NC-SA Compatible License.
-
-       2. You must include the text of, or the URI or hyperlink to, the
-          Adapter's License You apply. You may satisfy this condition
-          in any reasonable manner based on the medium, means, and
-          context in which You Share Adapted Material.
-
-       3. You may not offer or impose any additional or different terms
-          or conditions on, or apply any Effective Technological
-          Measures to, Adapted Material that restrict exercise of the
-          rights granted under the Adapter's License You apply.
-
-
-Section 4 -- Sui Generis Database Rights.
-
-Where the Licensed Rights include Sui Generis Database Rights that
-apply to Your use of the Licensed Material:
-
-  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
-     to extract, reuse, reproduce, and Share all or a substantial
-     portion of the contents of the database for NonCommercial purposes
-     only;
-
-  b. if You include all or a substantial portion of the database
-     contents in a database in which You have Sui Generis Database
-     Rights, then the database in which You have Sui Generis Database
-     Rights (but not its individual contents) is Adapted Material,
-     including for purposes of Section 3(b); and
-
-  c. You must comply with the conditions in Section 3(a) if You Share
-     all or a substantial portion of the contents of the database.
-
-For the avoidance of doubt, this Section 4 supplements and does not
-replace Your obligations under this Public License where the Licensed
-Rights include other Copyright and Similar Rights.
-
-
-Section 5 -- Disclaimer of Warranties and Limitation of Liability.
-
-  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
-     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
-     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
-     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
-     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
-     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
-     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
-     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
-     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
-     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
-
-  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
-     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
-     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
-     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
-     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
-     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
-     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
-     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
-     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
-
-  c. The disclaimer of warranties and limitation of liability provided
-     above shall be interpreted in a manner that, to the extent
-     possible, most closely approximates an absolute disclaimer and
-     waiver of all liability.
-
-
-Section 6 -- Term and Termination.
-
-  a. This Public License applies for the term of the Copyright and
-     Similar Rights licensed here. However, if You fail to comply with
-     this Public License, then Your rights under this Public License
-     terminate automatically.
-
-  b. Where Your right to use the Licensed Material has terminated under
-     Section 6(a), it reinstates:
-
-       1. automatically as of the date the violation is cured, provided
-          it is cured within 30 days of Your discovery of the
-          violation; or
-
-       2. upon express reinstatement by the Licensor.
-
-     For the avoidance of doubt, this Section 6(b) does not affect any
-     right the Licensor may have to seek remedies for Your violations
-     of this Public License.
-
-  c. For the avoidance of doubt, the Licensor may also offer the
-     Licensed Material under separate terms or conditions or stop
-     distributing the Licensed Material at any time; however, doing so
-     will not terminate this Public License.
-
-  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
-     License.
-
-
-Section 7 -- Other Terms and Conditions.
-
-  a. The Licensor shall not be bound by any additional or different
-     terms or conditions communicated by You unless expressly agreed.
-
-  b. Any arrangements, understandings, or agreements regarding the
-     Licensed Material not stated herein are separate from and
-     independent of the terms and conditions of this Public License.
-
-
-Section 8 -- Interpretation.
-
-  a. For the avoidance of doubt, this Public License does not, and
-     shall not be interpreted to, reduce, limit, restrict, or impose
-     conditions on any use of the Licensed Material that could lawfully
-     be made without permission under this Public License.
-
-  b. To the extent possible, if any provision of this Public License is
-     deemed unenforceable, it shall be automatically reformed to the
-     minimum extent necessary to make it enforceable. If the provision
-     cannot be reformed, it shall be severed from this Public License
-     without affecting the enforceability of the remaining terms and
-     conditions.
-
-  c. No term or condition of this Public License will be waived and no
-     failure to comply consented to unless expressly agreed to by the
-     Licensor.
-
-  d. Nothing in this Public License constitutes or may be interpreted
-     as a limitation upon, or waiver of, any privileges and immunities
-     that apply to the Licensor or You, including from the legal
-     processes of any jurisdiction or authority.
-
-=======================================================================
-
-Creative Commons is not a party to its public licenses.
-Notwithstanding, Creative Commons may elect to apply one of its public
-licenses to material it publishes and in those instances will be
-considered the "Licensor." Except for the limited purpose of indicating
-that material is shared under a Creative Commons public license or as
-otherwise permitted by the Creative Commons policies published at
-creativecommons.org/policies, Creative Commons does not authorize the
-use of the trademark "Creative Commons" or any other trademark or logo
-of Creative Commons without its prior written consent including,
-without limitation, in connection with any unauthorized modifications
-to any of its public licenses or any other arrangements,
-understandings, or agreements concerning use of licensed material. For
-the avoidance of doubt, this paragraph does not form part of the public
-licenses.
-
-Creative Commons may be contacted at creativecommons.org.
-
diff --git a/wearable/wear/JumpingJack/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/JumpingJack/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/JumpingJack/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/JumpingJack/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/Notifications/LICENSE b/wearable/wear/Notifications/LICENSE
index 4f22946..d5cf8f3 100644
--- a/wearable/wear/Notifications/LICENSE
+++ b/wearable/wear/Notifications/LICENSE
@@ -201,447 +201,3 @@
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-
-All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav 
-and *.ogg) are licensed under the CC-BY-NC license. All other files are 
-licensed under the Apache 2 license.
-
-CC-BY-NC License
-----------------
-
-Attribution-NonCommercial-ShareAlike 4.0 International
-
-=======================================================================
-
-Creative Commons Corporation ("Creative Commons") is not a law firm and
-does not provide legal services or legal advice. Distribution of
-Creative Commons public licenses does not create a lawyer-client or
-other relationship. Creative Commons makes its licenses and related
-information available on an "as-is" basis. Creative Commons gives no
-warranties regarding its licenses, any material licensed under their
-terms and conditions, or any related information. Creative Commons
-disclaims all liability for damages resulting from their use to the
-fullest extent possible.
-
-Using Creative Commons Public Licenses
-
-Creative Commons public licenses provide a standard set of terms and
-conditions that creators and other rights holders may use to share
-original works of authorship and other material subject to copyright
-and certain other rights specified in the public license below. The
-following considerations are for informational purposes only, are not
-exhaustive, and do not form part of our licenses.
-
-     Considerations for licensors: Our public licenses are
-     intended for use by those authorized to give the public
-     permission to use material in ways otherwise restricted by
-     copyright and certain other rights. Our licenses are
-     irrevocable. Licensors should read and understand the terms
-     and conditions of the license they choose before applying it.
-     Licensors should also secure all rights necessary before
-     applying our licenses so that the public can reuse the
-     material as expected. Licensors should clearly mark any
-     material not subject to the license. This includes other CC-
-     licensed material, or material used under an exception or
-     limitation to copyright. More considerations for licensors:
-	wiki.creativecommons.org/Considerations_for_licensors
-
-     Considerations for the public: By using one of our public
-     licenses, a licensor grants the public permission to use the
-     licensed material under specified terms and conditions. If
-     the licensor's permission is not necessary for any reason--for
-     example, because of any applicable exception or limitation to
-     copyright--then that use is not regulated by the license. Our
-     licenses grant only permissions under copyright and certain
-     other rights that a licensor has authority to grant. Use of
-     the licensed material may still be restricted for other
-     reasons, including because others have copyright or other
-     rights in the material. A licensor may make special requests,
-     such as asking that all changes be marked or described.
-     Although not required by our licenses, you are encouraged to
-     respect those requests where reasonable. More_considerations
-     for the public: 
-	wiki.creativecommons.org/Considerations_for_licensees
-
-=======================================================================
-
-Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
-Public License
-
-By exercising the Licensed Rights (defined below), You accept and agree
-to be bound by the terms and conditions of this Creative Commons
-Attribution-NonCommercial-ShareAlike 4.0 International Public License
-("Public License"). To the extent this Public License may be
-interpreted as a contract, You are granted the Licensed Rights in
-consideration of Your acceptance of these terms and conditions, and the
-Licensor grants You such rights in consideration of benefits the
-Licensor receives from making the Licensed Material available under
-these terms and conditions.
-
-
-Section 1 -- Definitions.
-
-  a. Adapted Material means material subject to Copyright and Similar
-     Rights that is derived from or based upon the Licensed Material
-     and in which the Licensed Material is translated, altered,
-     arranged, transformed, or otherwise modified in a manner requiring
-     permission under the Copyright and Similar Rights held by the
-     Licensor. For purposes of this Public License, where the Licensed
-     Material is a musical work, performance, or sound recording,
-     Adapted Material is always produced where the Licensed Material is
-     synched in timed relation with a moving image.
-
-  b. Adapter's License means the license You apply to Your Copyright
-     and Similar Rights in Your contributions to Adapted Material in
-     accordance with the terms and conditions of this Public License.
-
-  c. BY-NC-SA Compatible License means a license listed at
-     creativecommons.org/compatiblelicenses, approved by Creative
-     Commons as essentially the equivalent of this Public License.
-
-  d. Copyright and Similar Rights means copyright and/or similar rights
-     closely related to copyright including, without limitation,
-     performance, broadcast, sound recording, and Sui Generis Database
-     Rights, without regard to how the rights are labeled or
-     categorized. For purposes of this Public License, the rights
-     specified in Section 2(b)(1)-(2) are not Copyright and Similar
-     Rights.
-
-  e. Effective Technological Measures means those measures that, in the
-     absence of proper authority, may not be circumvented under laws
-     fulfilling obligations under Article 11 of the WIPO Copyright
-     Treaty adopted on December 20, 1996, and/or similar international
-     agreements.
-
-  f. Exceptions and Limitations means fair use, fair dealing, and/or
-     any other exception or limitation to Copyright and Similar Rights
-     that applies to Your use of the Licensed Material.
-
-  g. License Elements means the license attributes listed in the name
-     of a Creative Commons Public License. The License Elements of this
-     Public License are Attribution, NonCommercial, and ShareAlike.
-
-  h. Licensed Material means the artistic or literary work, database,
-     or other material to which the Licensor applied this Public
-     License.
-
-  i. Licensed Rights means the rights granted to You subject to the
-     terms and conditions of this Public License, which are limited to
-     all Copyright and Similar Rights that apply to Your use of the
-     Licensed Material and that the Licensor has authority to license.
-
-  j. Licensor means the individual(s) or entity(ies) granting rights
-     under this Public License.
-
-  k. NonCommercial means not primarily intended for or directed towards
-     commercial advantage or monetary compensation. For purposes of
-     this Public License, the exchange of the Licensed Material for
-     other material subject to Copyright and Similar Rights by digital
-     file-sharing or similar means is NonCommercial provided there is
-     no payment of monetary compensation in connection with the
-     exchange.
-
-  l. Share means to provide material to the public by any means or
-     process that requires permission under the Licensed Rights, such
-     as reproduction, public display, public performance, distribution,
-     dissemination, communication, or importation, and to make material
-     available to the public including in ways that members of the
-     public may access the material from a place and at a time
-     individually chosen by them.
-
-  m. Sui Generis Database Rights means rights other than copyright
-     resulting from Directive 96/9/EC of the European Parliament and of
-     the Council of 11 March 1996 on the legal protection of databases,
-     as amended and/or succeeded, as well as other essentially
-     equivalent rights anywhere in the world.
-
-  n. You means the individual or entity exercising the Licensed Rights
-     under this Public License. Your has a corresponding meaning.
-
-
-Section 2 -- Scope.
-
-  a. License grant.
-
-       1. Subject to the terms and conditions of this Public License,
-          the Licensor hereby grants You a worldwide, royalty-free,
-          non-sublicensable, non-exclusive, irrevocable license to
-          exercise the Licensed Rights in the Licensed Material to:
-
-            a. reproduce and Share the Licensed Material, in whole or
-               in part, for NonCommercial purposes only; and
-
-            b. produce, reproduce, and Share Adapted Material for
-               NonCommercial purposes only.
-
-       2. Exceptions and Limitations. For the avoidance of doubt, where
-          Exceptions and Limitations apply to Your use, this Public
-          License does not apply, and You do not need to comply with
-          its terms and conditions.
-
-       3. Term. The term of this Public License is specified in Section
-          6(a).
-
-       4. Media and formats; technical modifications allowed. The
-          Licensor authorizes You to exercise the Licensed Rights in
-          all media and formats whether now known or hereafter created,
-          and to make technical modifications necessary to do so. The
-          Licensor waives and/or agrees not to assert any right or
-          authority to forbid You from making technical modifications
-          necessary to exercise the Licensed Rights, including
-          technical modifications necessary to circumvent Effective
-          Technological Measures. For purposes of this Public License,
-          simply making modifications authorized by this Section 2(a)
-          (4) never produces Adapted Material.
-
-       5. Downstream recipients.
-
-            a. Offer from the Licensor -- Licensed Material. Every
-               recipient of the Licensed Material automatically
-               receives an offer from the Licensor to exercise the
-               Licensed Rights under the terms and conditions of this
-               Public License.
-
-            b. Additional offer from the Licensor -- Adapted Material.
-               Every recipient of Adapted Material from You
-               automatically receives an offer from the Licensor to
-               exercise the Licensed Rights in the Adapted Material
-               under the conditions of the Adapter's License You apply.
-
-            c. No downstream restrictions. You may not offer or impose
-               any additional or different terms or conditions on, or
-               apply any Effective Technological Measures to, the
-               Licensed Material if doing so restricts exercise of the
-               Licensed Rights by any recipient of the Licensed
-               Material.
-
-       6. No endorsement. Nothing in this Public License constitutes or
-          may be construed as permission to assert or imply that You
-          are, or that Your use of the Licensed Material is, connected
-          with, or sponsored, endorsed, or granted official status by,
-          the Licensor or others designated to receive attribution as
-          provided in Section 3(a)(1)(A)(i).
-
-  b. Other rights.
-
-       1. Moral rights, such as the right of integrity, are not
-          licensed under this Public License, nor are publicity,
-          privacy, and/or other similar personality rights; however, to
-          the extent possible, the Licensor waives and/or agrees not to
-          assert any such rights held by the Licensor to the limited
-          extent necessary to allow You to exercise the Licensed
-          Rights, but not otherwise.
-
-       2. Patent and trademark rights are not licensed under this
-          Public License.
-
-       3. To the extent possible, the Licensor waives any right to
-          collect royalties from You for the exercise of the Licensed
-          Rights, whether directly or through a collecting society
-          under any voluntary or waivable statutory or compulsory
-          licensing scheme. In all other cases the Licensor expressly
-          reserves any right to collect such royalties, including when
-          the Licensed Material is used other than for NonCommercial
-          purposes.
-
-
-Section 3 -- License Conditions.
-
-Your exercise of the Licensed Rights is expressly made subject to the
-following conditions.
-
-  a. Attribution.
-
-       1. If You Share the Licensed Material (including in modified
-          form), You must:
-
-            a. retain the following if it is supplied by the Licensor
-               with the Licensed Material:
-
-                 i. identification of the creator(s) of the Licensed
-                    Material and any others designated to receive
-                    attribution, in any reasonable manner requested by
-                    the Licensor (including by pseudonym if
-                    designated);
-
-                ii. a copyright notice;
-
-               iii. a notice that refers to this Public License;
-
-                iv. a notice that refers to the disclaimer of
-                    warranties;
-
-                 v. a URI or hyperlink to the Licensed Material to the
-                    extent reasonably practicable;
-
-            b. indicate if You modified the Licensed Material and
-               retain an indication of any previous modifications; and
-
-            c. indicate the Licensed Material is licensed under this
-               Public License, and include the text of, or the URI or
-               hyperlink to, this Public License.
-
-       2. You may satisfy the conditions in Section 3(a)(1) in any
-          reasonable manner based on the medium, means, and context in
-          which You Share the Licensed Material. For example, it may be
-          reasonable to satisfy the conditions by providing a URI or
-          hyperlink to a resource that includes the required
-          information.
-       3. If requested by the Licensor, You must remove any of the
-          information required by Section 3(a)(1)(A) to the extent
-          reasonably practicable.
-
-  b. ShareAlike.
-
-     In addition to the conditions in Section 3(a), if You Share
-     Adapted Material You produce, the following conditions also apply.
-
-       1. The Adapter's License You apply must be a Creative Commons
-          license with the same License Elements, this version or
-          later, or a BY-NC-SA Compatible License.
-
-       2. You must include the text of, or the URI or hyperlink to, the
-          Adapter's License You apply. You may satisfy this condition
-          in any reasonable manner based on the medium, means, and
-          context in which You Share Adapted Material.
-
-       3. You may not offer or impose any additional or different terms
-          or conditions on, or apply any Effective Technological
-          Measures to, Adapted Material that restrict exercise of the
-          rights granted under the Adapter's License You apply.
-
-
-Section 4 -- Sui Generis Database Rights.
-
-Where the Licensed Rights include Sui Generis Database Rights that
-apply to Your use of the Licensed Material:
-
-  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
-     to extract, reuse, reproduce, and Share all or a substantial
-     portion of the contents of the database for NonCommercial purposes
-     only;
-
-  b. if You include all or a substantial portion of the database
-     contents in a database in which You have Sui Generis Database
-     Rights, then the database in which You have Sui Generis Database
-     Rights (but not its individual contents) is Adapted Material,
-     including for purposes of Section 3(b); and
-
-  c. You must comply with the conditions in Section 3(a) if You Share
-     all or a substantial portion of the contents of the database.
-
-For the avoidance of doubt, this Section 4 supplements and does not
-replace Your obligations under this Public License where the Licensed
-Rights include other Copyright and Similar Rights.
-
-
-Section 5 -- Disclaimer of Warranties and Limitation of Liability.
-
-  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
-     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
-     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
-     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
-     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
-     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
-     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
-     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
-     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
-     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
-
-  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
-     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
-     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
-     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
-     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
-     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
-     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
-     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
-     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
-
-  c. The disclaimer of warranties and limitation of liability provided
-     above shall be interpreted in a manner that, to the extent
-     possible, most closely approximates an absolute disclaimer and
-     waiver of all liability.
-
-
-Section 6 -- Term and Termination.
-
-  a. This Public License applies for the term of the Copyright and
-     Similar Rights licensed here. However, if You fail to comply with
-     this Public License, then Your rights under this Public License
-     terminate automatically.
-
-  b. Where Your right to use the Licensed Material has terminated under
-     Section 6(a), it reinstates:
-
-       1. automatically as of the date the violation is cured, provided
-          it is cured within 30 days of Your discovery of the
-          violation; or
-
-       2. upon express reinstatement by the Licensor.
-
-     For the avoidance of doubt, this Section 6(b) does not affect any
-     right the Licensor may have to seek remedies for Your violations
-     of this Public License.
-
-  c. For the avoidance of doubt, the Licensor may also offer the
-     Licensed Material under separate terms or conditions or stop
-     distributing the Licensed Material at any time; however, doing so
-     will not terminate this Public License.
-
-  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
-     License.
-
-
-Section 7 -- Other Terms and Conditions.
-
-  a. The Licensor shall not be bound by any additional or different
-     terms or conditions communicated by You unless expressly agreed.
-
-  b. Any arrangements, understandings, or agreements regarding the
-     Licensed Material not stated herein are separate from and
-     independent of the terms and conditions of this Public License.
-
-
-Section 8 -- Interpretation.
-
-  a. For the avoidance of doubt, this Public License does not, and
-     shall not be interpreted to, reduce, limit, restrict, or impose
-     conditions on any use of the Licensed Material that could lawfully
-     be made without permission under this Public License.
-
-  b. To the extent possible, if any provision of this Public License is
-     deemed unenforceable, it shall be automatically reformed to the
-     minimum extent necessary to make it enforceable. If the provision
-     cannot be reformed, it shall be severed from this Public License
-     without affecting the enforceability of the remaining terms and
-     conditions.
-
-  c. No term or condition of this Public License will be waived and no
-     failure to comply consented to unless expressly agreed to by the
-     Licensor.
-
-  d. Nothing in this Public License constitutes or may be interpreted
-     as a limitation upon, or waiver of, any privileges and immunities
-     that apply to the Licensor or You, including from the legal
-     processes of any jurisdiction or authority.
-
-=======================================================================
-
-Creative Commons is not a party to its public licenses.
-Notwithstanding, Creative Commons may elect to apply one of its public
-licenses to material it publishes and in those instances will be
-considered the "Licensor." Except for the limited purpose of indicating
-that material is shared under a Creative Commons public license or as
-otherwise permitted by the Creative Commons policies published at
-creativecommons.org/policies, Creative Commons does not authorize the
-use of the trademark "Creative Commons" or any other trademark or logo
-of Creative Commons without its prior written consent including,
-without limitation, in connection with any unauthorized modifications
-to any of its public licenses or any other arrangements,
-understandings, or agreements concerning use of licensed material. For
-the avoidance of doubt, this paragraph does not form part of the public
-licenses.
-
-Creative Commons may be contacted at creativecommons.org.
-
diff --git a/wearable/wear/Notifications/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/Notifications/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/Notifications/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/Notifications/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/Notifications/template-params.xml b/wearable/wear/Notifications/template-params.xml
index 90f9d96..35088a9 100644
--- a/wearable/wear/Notifications/template-params.xml
+++ b/wearable/wear/Notifications/template-params.xml
@@ -23,8 +23,11 @@
     <package>com.example.android.support.wearable.notifications</package>
 
     <minSdk>18</minSdk>
-    <targetSdkVersion>25</targetSdkVersion>
-    <targetSdkVersionWear>25</targetSdkVersionWear>
+    <targetSdkVersion>27</targetSdkVersion>
+
+    <minSdkVersionWear>23</minSdkVersionWear>
+    <compileSdkVersionWear>26</compileSdkVersionWear>
+    <targetSdkVersionWear>26</targetSdkVersionWear>
 
     <wearable>
         <has_handheld_app>true</has_handheld_app>
@@ -36,7 +39,7 @@
         <intro>
             <![CDATA[
 This sample application provides a showcase of available notification styles and
-demonstrates various features of the Android Wear notifications API. Running the sample on your
+demonstrates various features of the Wear notifications API. Running the sample on your
 companion allows you to select between various notification styles and to see how these
 notifications are displayed, both in a phone\'s notification shade and on the wearable.
             ]]>
diff --git a/wearable/wear/Quiz/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/Quiz/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/Quiz/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/Quiz/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/RecipeAssistant/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/RecipeAssistant/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/RecipeAssistant/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/RecipeAssistant/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/RuntimePermissionsWear/Shared/build.gradle b/wearable/wear/RuntimePermissionsWear/Shared/build.gradle
index 52e76e2..95588db 100644
--- a/wearable/wear/RuntimePermissionsWear/Shared/build.gradle
+++ b/wearable/wear/RuntimePermissionsWear/Shared/build.gradle
@@ -2,10 +2,11 @@
 buildscript {
     repositories {
         jcenter()
+        google()
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.1'
     }
 }
 
@@ -13,9 +14,7 @@
 
 repositories {
     jcenter()
-    maven {
-        url 'https://maven.google.com'
-    }
+    google()
 }
 
 
@@ -29,13 +28,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 25
+    compileSdkVersion 27
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "27.0.3"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 27
     }
 
     compileOptions {
diff --git a/wearable/wear/RuntimePermissionsWear/Wearable/src/main/java/com/example/android/wearable/runtimepermissions/MainWearActivity.java b/wearable/wear/RuntimePermissionsWear/Wearable/src/main/java/com/example/android/wearable/runtimepermissions/MainWearActivity.java
index 774715f..95a152b 100644
--- a/wearable/wear/RuntimePermissionsWear/Wearable/src/main/java/com/example/android/wearable/runtimepermissions/MainWearActivity.java
+++ b/wearable/wear/RuntimePermissionsWear/Wearable/src/main/java/com/example/android/wearable/runtimepermissions/MainWearActivity.java
@@ -17,6 +17,7 @@
 package com.example.android.wearable.runtimepermissions;
 
 import android.Manifest;
+import android.app.Activity;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.hardware.Sensor;
@@ -25,7 +26,7 @@
 import android.os.Looper;
 import android.support.annotation.NonNull;
 import android.support.v4.app.ActivityCompat;
-import android.support.wearable.activity.WearableActivity;
+import android.support.wear.ambient.AmbientMode;
 import android.util.Log;
 import android.view.View;
 import android.widget.Button;
@@ -58,7 +59,8 @@
  * this Activity also sends back the results of the permission request to the phone device (and
  * the sensor data if approved).
  */
-public class MainWearActivity extends WearableActivity implements
+public class MainWearActivity extends Activity implements
+        AmbientMode.AmbientCallbackProvider,
         GoogleApiClient.ConnectionCallbacks,
         GoogleApiClient.OnConnectionFailedListener,
         CapabilityApi.CapabilityListener,
@@ -76,6 +78,12 @@
     public static final String EXTRA_PROMPT_PERMISSION_FROM_PHONE =
             "com.example.android.wearable.runtimepermissions.extra.PROMPT_PERMISSION_FROM_PHONE";
 
+    /**
+     * Ambient mode controller attached to this display. Used by the Activity to see if it is in
+     * ambient mode.
+     */
+    private AmbientMode.AmbientController mAmbientController;
+
     private boolean mWearBodySensorsPermissionApproved;
     private boolean mPhoneStoragePermissionApproved;
 
@@ -101,7 +109,9 @@
         mPhoneStoragePermissionApproved = false;
 
         setContentView(R.layout.activity_main);
-        setAmbientEnabled();
+
+        // Enables Ambient mode.
+        mAmbientController = AmbientMode.attachAmbientSupport(this);
 
         // Checks if phone app requested wear permission (permission request opens later if true).
         mPhoneRequestingWearSensorPermission =
@@ -208,49 +218,6 @@
         }
     }
 
-    @Override
-    public void onEnterAmbient(Bundle ambientDetails) {
-        Log.d(TAG, "onEnterAmbient() " + ambientDetails);
-
-        if (mWearBodySensorsPermissionApproved) {
-            mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
-                    R.drawable.ic_permission_approved_bw, 0, 0, 0);
-        } else {
-            mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
-                    R.drawable.ic_permission_denied_bw, 0, 0, 0);
-        }
-
-        if (mPhoneStoragePermissionApproved) {
-            mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
-                    R.drawable.ic_permission_approved_bw, 0, 0, 0);
-        } else {
-            mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
-                    R.drawable.ic_permission_denied_bw, 0, 0, 0);
-        }
-        super.onEnterAmbient(ambientDetails);
-    }
-
-    @Override
-    public void onExitAmbient() {
-        Log.d(TAG, "onExitAmbient()");
-
-        if (mWearBodySensorsPermissionApproved) {
-            mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
-                    R.drawable.ic_permission_approved, 0, 0, 0);
-        } else {
-            mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
-                    R.drawable.ic_permission_denied, 0, 0, 0);
-        }
-
-        if (mPhoneStoragePermissionApproved) {
-            mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
-                    R.drawable.ic_permission_approved, 0, 0, 0);
-        } else {
-            mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
-                    R.drawable.ic_permission_denied, 0, 0, 0);
-        }
-        super.onExitAmbient();
-    }
 
     @Override
     public void onConnected(Bundle bundle) {
@@ -495,7 +462,7 @@
 
                 if (mPhoneStoragePermissionApproved) {
 
-                    if (isAmbient()) {
+                    if (mAmbientController.isAmbient()) {
                         mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
                                 R.drawable.ic_permission_approved_bw, 0, 0, 0);
                     } else {
@@ -505,7 +472,7 @@
 
                 } else {
 
-                    if (isAmbient()) {
+                    if (mAmbientController.isAmbient()) {
                         mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
                                 R.drawable.ic_permission_denied_bw, 0, 0, 0);
                     } else {
@@ -517,6 +484,63 @@
         });
     }
 
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {
+        /** Prepares the UI for ambient mode. */
+        @Override
+        public void onEnterAmbient(Bundle ambientDetails) {
+            super.onEnterAmbient(ambientDetails);
+
+            Log.d(TAG, "onEnterAmbient() " + ambientDetails);
+
+            if (mWearBodySensorsPermissionApproved) {
+                mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
+                        R.drawable.ic_permission_approved_bw, 0, 0, 0);
+            } else {
+                mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
+                        R.drawable.ic_permission_denied_bw, 0, 0, 0);
+            }
+
+            if (mPhoneStoragePermissionApproved) {
+                mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
+                        R.drawable.ic_permission_approved_bw, 0, 0, 0);
+            } else {
+                mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
+                        R.drawable.ic_permission_denied_bw, 0, 0, 0);
+            }
+        }
+
+        /** Restores the UI to active (non-ambient) mode. */
+        @Override
+        public void onExitAmbient() {
+            super.onExitAmbient();
+
+            Log.d(TAG, "onExitAmbient()");
+
+            if (mWearBodySensorsPermissionApproved) {
+                mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
+                        R.drawable.ic_permission_approved, 0, 0, 0);
+            } else {
+                mWearBodySensorsPermissionButton.setCompoundDrawablesWithIntrinsicBounds(
+                        R.drawable.ic_permission_denied, 0, 0, 0);
+            }
+
+            if (mPhoneStoragePermissionApproved) {
+                mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
+                        R.drawable.ic_permission_approved, 0, 0, 0);
+            } else {
+                mPhoneStoragePermissionButton.setCompoundDrawablesWithIntrinsicBounds(
+                        R.drawable.ic_permission_denied, 0, 0, 0);
+            }
+
+        }
+    }
+
+
     /*
      * Handles all messages for the UI coming on and off the main thread. Not all callbacks happen
      * on the main thread.
diff --git a/wearable/wear/RuntimePermissionsWear/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/RuntimePermissionsWear/gradle/wrapper/gradle-wrapper.properties
index 4cd882f..1ee44fe 100644
--- a/wearable/wear/RuntimePermissionsWear/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/RuntimePermissionsWear/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/RuntimePermissionsWear/template-params.xml b/wearable/wear/RuntimePermissionsWear/template-params.xml
index 73e075a..0a1863c 100644
--- a/wearable/wear/RuntimePermissionsWear/template-params.xml
+++ b/wearable/wear/RuntimePermissionsWear/template-params.xml
@@ -21,7 +21,7 @@
     <package>com.example.android.wearable.runtimepermissions</package>
 
     <minSdk>18</minSdk>
-    <targetSdkVersion>25</targetSdkVersion>
+    <targetSdkVersion>27</targetSdkVersion>
 
     <minSdkVersionWear>23</minSdkVersionWear>
     <compileSdkVersionWear>26</compileSdkVersionWear>
@@ -32,10 +32,10 @@
         <has_handheld_app>true</has_handheld_app>
     </wearable>
 
-    <dependency>com.android.support:appcompat-v7:25.3.1</dependency>
-    <dependency>com.android.support:design:25.3.1</dependency>
+    <dependency>com.android.support:appcompat-v7:27.1,0</dependency>
+    <dependency>com.android.support:design:27.1.0</dependency>
 
-    <dependency_wearable>com.android.support:wear:26.0.0</dependency_wearable>
+    <dependency_wearable>com.android.support:wear:27.1.0</dependency_wearable>
 
     <strings>
         <intro>
diff --git a/wearable/wear/SkeletonWearableApp/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/SkeletonWearableApp/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/SkeletonWearableApp/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/SkeletonWearableApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/LICENSE b/wearable/wear/SpeedTracker/LICENSE
index 4f22946..d5cf8f3 100644
--- a/wearable/wear/SpeedTracker/LICENSE
+++ b/wearable/wear/SpeedTracker/LICENSE
@@ -201,447 +201,3 @@
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-
-All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav 
-and *.ogg) are licensed under the CC-BY-NC license. All other files are 
-licensed under the Apache 2 license.
-
-CC-BY-NC License
-----------------
-
-Attribution-NonCommercial-ShareAlike 4.0 International
-
-=======================================================================
-
-Creative Commons Corporation ("Creative Commons") is not a law firm and
-does not provide legal services or legal advice. Distribution of
-Creative Commons public licenses does not create a lawyer-client or
-other relationship. Creative Commons makes its licenses and related
-information available on an "as-is" basis. Creative Commons gives no
-warranties regarding its licenses, any material licensed under their
-terms and conditions, or any related information. Creative Commons
-disclaims all liability for damages resulting from their use to the
-fullest extent possible.
-
-Using Creative Commons Public Licenses
-
-Creative Commons public licenses provide a standard set of terms and
-conditions that creators and other rights holders may use to share
-original works of authorship and other material subject to copyright
-and certain other rights specified in the public license below. The
-following considerations are for informational purposes only, are not
-exhaustive, and do not form part of our licenses.
-
-     Considerations for licensors: Our public licenses are
-     intended for use by those authorized to give the public
-     permission to use material in ways otherwise restricted by
-     copyright and certain other rights. Our licenses are
-     irrevocable. Licensors should read and understand the terms
-     and conditions of the license they choose before applying it.
-     Licensors should also secure all rights necessary before
-     applying our licenses so that the public can reuse the
-     material as expected. Licensors should clearly mark any
-     material not subject to the license. This includes other CC-
-     licensed material, or material used under an exception or
-     limitation to copyright. More considerations for licensors:
-	wiki.creativecommons.org/Considerations_for_licensors
-
-     Considerations for the public: By using one of our public
-     licenses, a licensor grants the public permission to use the
-     licensed material under specified terms and conditions. If
-     the licensor's permission is not necessary for any reason--for
-     example, because of any applicable exception or limitation to
-     copyright--then that use is not regulated by the license. Our
-     licenses grant only permissions under copyright and certain
-     other rights that a licensor has authority to grant. Use of
-     the licensed material may still be restricted for other
-     reasons, including because others have copyright or other
-     rights in the material. A licensor may make special requests,
-     such as asking that all changes be marked or described.
-     Although not required by our licenses, you are encouraged to
-     respect those requests where reasonable. More_considerations
-     for the public: 
-	wiki.creativecommons.org/Considerations_for_licensees
-
-=======================================================================
-
-Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
-Public License
-
-By exercising the Licensed Rights (defined below), You accept and agree
-to be bound by the terms and conditions of this Creative Commons
-Attribution-NonCommercial-ShareAlike 4.0 International Public License
-("Public License"). To the extent this Public License may be
-interpreted as a contract, You are granted the Licensed Rights in
-consideration of Your acceptance of these terms and conditions, and the
-Licensor grants You such rights in consideration of benefits the
-Licensor receives from making the Licensed Material available under
-these terms and conditions.
-
-
-Section 1 -- Definitions.
-
-  a. Adapted Material means material subject to Copyright and Similar
-     Rights that is derived from or based upon the Licensed Material
-     and in which the Licensed Material is translated, altered,
-     arranged, transformed, or otherwise modified in a manner requiring
-     permission under the Copyright and Similar Rights held by the
-     Licensor. For purposes of this Public License, where the Licensed
-     Material is a musical work, performance, or sound recording,
-     Adapted Material is always produced where the Licensed Material is
-     synched in timed relation with a moving image.
-
-  b. Adapter's License means the license You apply to Your Copyright
-     and Similar Rights in Your contributions to Adapted Material in
-     accordance with the terms and conditions of this Public License.
-
-  c. BY-NC-SA Compatible License means a license listed at
-     creativecommons.org/compatiblelicenses, approved by Creative
-     Commons as essentially the equivalent of this Public License.
-
-  d. Copyright and Similar Rights means copyright and/or similar rights
-     closely related to copyright including, without limitation,
-     performance, broadcast, sound recording, and Sui Generis Database
-     Rights, without regard to how the rights are labeled or
-     categorized. For purposes of this Public License, the rights
-     specified in Section 2(b)(1)-(2) are not Copyright and Similar
-     Rights.
-
-  e. Effective Technological Measures means those measures that, in the
-     absence of proper authority, may not be circumvented under laws
-     fulfilling obligations under Article 11 of the WIPO Copyright
-     Treaty adopted on December 20, 1996, and/or similar international
-     agreements.
-
-  f. Exceptions and Limitations means fair use, fair dealing, and/or
-     any other exception or limitation to Copyright and Similar Rights
-     that applies to Your use of the Licensed Material.
-
-  g. License Elements means the license attributes listed in the name
-     of a Creative Commons Public License. The License Elements of this
-     Public License are Attribution, NonCommercial, and ShareAlike.
-
-  h. Licensed Material means the artistic or literary work, database,
-     or other material to which the Licensor applied this Public
-     License.
-
-  i. Licensed Rights means the rights granted to You subject to the
-     terms and conditions of this Public License, which are limited to
-     all Copyright and Similar Rights that apply to Your use of the
-     Licensed Material and that the Licensor has authority to license.
-
-  j. Licensor means the individual(s) or entity(ies) granting rights
-     under this Public License.
-
-  k. NonCommercial means not primarily intended for or directed towards
-     commercial advantage or monetary compensation. For purposes of
-     this Public License, the exchange of the Licensed Material for
-     other material subject to Copyright and Similar Rights by digital
-     file-sharing or similar means is NonCommercial provided there is
-     no payment of monetary compensation in connection with the
-     exchange.
-
-  l. Share means to provide material to the public by any means or
-     process that requires permission under the Licensed Rights, such
-     as reproduction, public display, public performance, distribution,
-     dissemination, communication, or importation, and to make material
-     available to the public including in ways that members of the
-     public may access the material from a place and at a time
-     individually chosen by them.
-
-  m. Sui Generis Database Rights means rights other than copyright
-     resulting from Directive 96/9/EC of the European Parliament and of
-     the Council of 11 March 1996 on the legal protection of databases,
-     as amended and/or succeeded, as well as other essentially
-     equivalent rights anywhere in the world.
-
-  n. You means the individual or entity exercising the Licensed Rights
-     under this Public License. Your has a corresponding meaning.
-
-
-Section 2 -- Scope.
-
-  a. License grant.
-
-       1. Subject to the terms and conditions of this Public License,
-          the Licensor hereby grants You a worldwide, royalty-free,
-          non-sublicensable, non-exclusive, irrevocable license to
-          exercise the Licensed Rights in the Licensed Material to:
-
-            a. reproduce and Share the Licensed Material, in whole or
-               in part, for NonCommercial purposes only; and
-
-            b. produce, reproduce, and Share Adapted Material for
-               NonCommercial purposes only.
-
-       2. Exceptions and Limitations. For the avoidance of doubt, where
-          Exceptions and Limitations apply to Your use, this Public
-          License does not apply, and You do not need to comply with
-          its terms and conditions.
-
-       3. Term. The term of this Public License is specified in Section
-          6(a).
-
-       4. Media and formats; technical modifications allowed. The
-          Licensor authorizes You to exercise the Licensed Rights in
-          all media and formats whether now known or hereafter created,
-          and to make technical modifications necessary to do so. The
-          Licensor waives and/or agrees not to assert any right or
-          authority to forbid You from making technical modifications
-          necessary to exercise the Licensed Rights, including
-          technical modifications necessary to circumvent Effective
-          Technological Measures. For purposes of this Public License,
-          simply making modifications authorized by this Section 2(a)
-          (4) never produces Adapted Material.
-
-       5. Downstream recipients.
-
-            a. Offer from the Licensor -- Licensed Material. Every
-               recipient of the Licensed Material automatically
-               receives an offer from the Licensor to exercise the
-               Licensed Rights under the terms and conditions of this
-               Public License.
-
-            b. Additional offer from the Licensor -- Adapted Material.
-               Every recipient of Adapted Material from You
-               automatically receives an offer from the Licensor to
-               exercise the Licensed Rights in the Adapted Material
-               under the conditions of the Adapter's License You apply.
-
-            c. No downstream restrictions. You may not offer or impose
-               any additional or different terms or conditions on, or
-               apply any Effective Technological Measures to, the
-               Licensed Material if doing so restricts exercise of the
-               Licensed Rights by any recipient of the Licensed
-               Material.
-
-       6. No endorsement. Nothing in this Public License constitutes or
-          may be construed as permission to assert or imply that You
-          are, or that Your use of the Licensed Material is, connected
-          with, or sponsored, endorsed, or granted official status by,
-          the Licensor or others designated to receive attribution as
-          provided in Section 3(a)(1)(A)(i).
-
-  b. Other rights.
-
-       1. Moral rights, such as the right of integrity, are not
-          licensed under this Public License, nor are publicity,
-          privacy, and/or other similar personality rights; however, to
-          the extent possible, the Licensor waives and/or agrees not to
-          assert any such rights held by the Licensor to the limited
-          extent necessary to allow You to exercise the Licensed
-          Rights, but not otherwise.
-
-       2. Patent and trademark rights are not licensed under this
-          Public License.
-
-       3. To the extent possible, the Licensor waives any right to
-          collect royalties from You for the exercise of the Licensed
-          Rights, whether directly or through a collecting society
-          under any voluntary or waivable statutory or compulsory
-          licensing scheme. In all other cases the Licensor expressly
-          reserves any right to collect such royalties, including when
-          the Licensed Material is used other than for NonCommercial
-          purposes.
-
-
-Section 3 -- License Conditions.
-
-Your exercise of the Licensed Rights is expressly made subject to the
-following conditions.
-
-  a. Attribution.
-
-       1. If You Share the Licensed Material (including in modified
-          form), You must:
-
-            a. retain the following if it is supplied by the Licensor
-               with the Licensed Material:
-
-                 i. identification of the creator(s) of the Licensed
-                    Material and any others designated to receive
-                    attribution, in any reasonable manner requested by
-                    the Licensor (including by pseudonym if
-                    designated);
-
-                ii. a copyright notice;
-
-               iii. a notice that refers to this Public License;
-
-                iv. a notice that refers to the disclaimer of
-                    warranties;
-
-                 v. a URI or hyperlink to the Licensed Material to the
-                    extent reasonably practicable;
-
-            b. indicate if You modified the Licensed Material and
-               retain an indication of any previous modifications; and
-
-            c. indicate the Licensed Material is licensed under this
-               Public License, and include the text of, or the URI or
-               hyperlink to, this Public License.
-
-       2. You may satisfy the conditions in Section 3(a)(1) in any
-          reasonable manner based on the medium, means, and context in
-          which You Share the Licensed Material. For example, it may be
-          reasonable to satisfy the conditions by providing a URI or
-          hyperlink to a resource that includes the required
-          information.
-       3. If requested by the Licensor, You must remove any of the
-          information required by Section 3(a)(1)(A) to the extent
-          reasonably practicable.
-
-  b. ShareAlike.
-
-     In addition to the conditions in Section 3(a), if You Share
-     Adapted Material You produce, the following conditions also apply.
-
-       1. The Adapter's License You apply must be a Creative Commons
-          license with the same License Elements, this version or
-          later, or a BY-NC-SA Compatible License.
-
-       2. You must include the text of, or the URI or hyperlink to, the
-          Adapter's License You apply. You may satisfy this condition
-          in any reasonable manner based on the medium, means, and
-          context in which You Share Adapted Material.
-
-       3. You may not offer or impose any additional or different terms
-          or conditions on, or apply any Effective Technological
-          Measures to, Adapted Material that restrict exercise of the
-          rights granted under the Adapter's License You apply.
-
-
-Section 4 -- Sui Generis Database Rights.
-
-Where the Licensed Rights include Sui Generis Database Rights that
-apply to Your use of the Licensed Material:
-
-  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
-     to extract, reuse, reproduce, and Share all or a substantial
-     portion of the contents of the database for NonCommercial purposes
-     only;
-
-  b. if You include all or a substantial portion of the database
-     contents in a database in which You have Sui Generis Database
-     Rights, then the database in which You have Sui Generis Database
-     Rights (but not its individual contents) is Adapted Material,
-     including for purposes of Section 3(b); and
-
-  c. You must comply with the conditions in Section 3(a) if You Share
-     all or a substantial portion of the contents of the database.
-
-For the avoidance of doubt, this Section 4 supplements and does not
-replace Your obligations under this Public License where the Licensed
-Rights include other Copyright and Similar Rights.
-
-
-Section 5 -- Disclaimer of Warranties and Limitation of Liability.
-
-  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
-     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
-     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
-     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
-     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
-     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
-     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
-     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
-     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
-     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
-
-  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
-     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
-     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
-     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
-     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
-     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
-     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
-     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
-     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
-
-  c. The disclaimer of warranties and limitation of liability provided
-     above shall be interpreted in a manner that, to the extent
-     possible, most closely approximates an absolute disclaimer and
-     waiver of all liability.
-
-
-Section 6 -- Term and Termination.
-
-  a. This Public License applies for the term of the Copyright and
-     Similar Rights licensed here. However, if You fail to comply with
-     this Public License, then Your rights under this Public License
-     terminate automatically.
-
-  b. Where Your right to use the Licensed Material has terminated under
-     Section 6(a), it reinstates:
-
-       1. automatically as of the date the violation is cured, provided
-          it is cured within 30 days of Your discovery of the
-          violation; or
-
-       2. upon express reinstatement by the Licensor.
-
-     For the avoidance of doubt, this Section 6(b) does not affect any
-     right the Licensor may have to seek remedies for Your violations
-     of this Public License.
-
-  c. For the avoidance of doubt, the Licensor may also offer the
-     Licensed Material under separate terms or conditions or stop
-     distributing the Licensed Material at any time; however, doing so
-     will not terminate this Public License.
-
-  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
-     License.
-
-
-Section 7 -- Other Terms and Conditions.
-
-  a. The Licensor shall not be bound by any additional or different
-     terms or conditions communicated by You unless expressly agreed.
-
-  b. Any arrangements, understandings, or agreements regarding the
-     Licensed Material not stated herein are separate from and
-     independent of the terms and conditions of this Public License.
-
-
-Section 8 -- Interpretation.
-
-  a. For the avoidance of doubt, this Public License does not, and
-     shall not be interpreted to, reduce, limit, restrict, or impose
-     conditions on any use of the Licensed Material that could lawfully
-     be made without permission under this Public License.
-
-  b. To the extent possible, if any provision of this Public License is
-     deemed unenforceable, it shall be automatically reformed to the
-     minimum extent necessary to make it enforceable. If the provision
-     cannot be reformed, it shall be severed from this Public License
-     without affecting the enforceability of the remaining terms and
-     conditions.
-
-  c. No term or condition of this Public License will be waived and no
-     failure to comply consented to unless expressly agreed to by the
-     Licensor.
-
-  d. Nothing in this Public License constitutes or may be interpreted
-     as a limitation upon, or waiver of, any privileges and immunities
-     that apply to the Licensor or You, including from the legal
-     processes of any jurisdiction or authority.
-
-=======================================================================
-
-Creative Commons is not a party to its public licenses.
-Notwithstanding, Creative Commons may elect to apply one of its public
-licenses to material it publishes and in those instances will be
-considered the "Licensor." Except for the limited purpose of indicating
-that material is shared under a Creative Commons public license or as
-otherwise permitted by the Creative Commons policies published at
-creativecommons.org/policies, Creative Commons does not authorize the
-use of the trademark "Creative Commons" or any other trademark or logo
-of Creative Commons without its prior written consent including,
-without limitation, in connection with any unauthorized modifications
-to any of its public licenses or any other arrangements,
-understandings, or agreements concerning use of licensed material. For
-the avoidance of doubt, this paragraph does not form part of the public
-licenses.
-
-Creative Commons may be contacted at creativecommons.org.
-
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/WearableMainActivity.java b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/WearableMainActivity.java
index 20ded86..d6e2f3f 100644
--- a/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/WearableMainActivity.java
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/WearableMainActivity.java
@@ -30,6 +30,7 @@
 
 import android.Manifest;
 import android.annotation.SuppressLint;
+import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -41,7 +42,8 @@
 import android.preference.PreferenceManager;
 import android.support.annotation.NonNull;
 import android.support.v4.app.ActivityCompat;
-import android.support.wearable.activity.WearableActivity;
+import android.support.v4.content.ContextCompat;
+import android.support.wear.ambient.AmbientMode;
 import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
@@ -60,7 +62,8 @@
  * and if the user exceeds the speed limit, it will turn red. In order to show the user that GPS
  * location data is coming in, a small green dot keeps on blinking while GPS data is available.
  */
-public class WearableMainActivity extends WearableActivity implements
+public class WearableMainActivity extends Activity implements
+        AmbientMode.AmbientCallbackProvider,
         GoogleApiClient.ConnectionCallbacks,
         GoogleApiClient.OnConnectionFailedListener,
         ActivityCompat.OnRequestPermissionsResultCallback,
@@ -105,6 +108,12 @@
 
     private boolean mWaitingForGpsSignal;
 
+    /**
+     * Ambient mode controller attached to this display. Used by the Activity to see if it is in
+     * ambient mode.
+     */
+    private AmbientMode.AmbientController mAmbientController;
+
     private GoogleApiClient mGoogleApiClient;
 
     private Handler mHandler = new Handler();
@@ -140,7 +149,8 @@
          * in ambient mode, check this page:
          * https://developer.android.com/training/wearables/apps/always-on.html
          */
-        setAmbientEnabled();
+        // Enables Ambient mode.
+        mAmbientController = AmbientMode.attachAmbientSupport(this);
 
         mCalendar = Calendar.getInstance();
 
@@ -494,4 +504,35 @@
     private boolean hasGps() {
         return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS);
     }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {
+        /** Prepares the UI for ambient mode. */
+        @Override
+        public void onEnterAmbient(Bundle ambientDetails) {
+            super.onEnterAmbient(ambientDetails);
+
+            Log.d(TAG, "onEnterAmbient() " + ambientDetails);
+
+            // Changes views to grey scale.
+            mSpeedTextView.setTextColor(
+                    ContextCompat.getColor(getApplicationContext(), R.color.white));
+        }
+
+        /** Restores the UI to active (non-ambient) mode. */
+        @Override
+        public void onExitAmbient() {
+            super.onExitAmbient();
+
+            Log.d(TAG, "onExitAmbient()");
+
+            // Changes views to color.
+            mSpeedTextView.setTextColor(
+                    ContextCompat.getColor(getApplicationContext(), R.color.green));
+        }
+    }
 }
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.properties
index 19db912..b88edce 100644
--- a/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/template-params.xml b/wearable/wear/SpeedTracker/template-params.xml
index 881d94e..253f13d 100644
--- a/wearable/wear/SpeedTracker/template-params.xml
+++ b/wearable/wear/SpeedTracker/template-params.xml
@@ -21,7 +21,7 @@
     <package>com.example.android.wearable.speedtracker</package>
 
     <minSdk>18</minSdk>
-    <targetSdkVersion>25</targetSdkVersion>
+    <targetSdkVersion>27</targetSdkVersion>
 
     <minSdkVersionWear>23</minSdkVersionWear>
     <compileSdkVersionWear>26</compileSdkVersionWear>
@@ -32,8 +32,8 @@
         <has_handheld_app>true</has_handheld_app>
     </wearable>
 
-    <dependency>com.android.support:design:25.3.1</dependency>
-    <dependency_wearable>com.android.support:wear:26.0.0</dependency_wearable>
+    <dependency>com.android.support:design:27.1.0</dependency>
+    <dependency_wearable>com.android.support:wear:27.1.0</dependency_wearable>
 
     <dependency>com.google.android.gms:play-services-maps</dependency>
     <dependency>com.google.android.gms:play-services-location</dependency>
diff --git a/wearable/wear/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.properties
index 143e341..3a22c63 100644
--- a/wearable/wear/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/SynchronizedNotifications/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/Timer/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/Timer/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/Timer/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/Timer/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/WatchFace/LICENSE b/wearable/wear/WatchFace/LICENSE
index 4f22946..d5cf8f3 100644
--- a/wearable/wear/WatchFace/LICENSE
+++ b/wearable/wear/WatchFace/LICENSE
@@ -201,447 +201,3 @@
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-
-All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav 
-and *.ogg) are licensed under the CC-BY-NC license. All other files are 
-licensed under the Apache 2 license.
-
-CC-BY-NC License
-----------------
-
-Attribution-NonCommercial-ShareAlike 4.0 International
-
-=======================================================================
-
-Creative Commons Corporation ("Creative Commons") is not a law firm and
-does not provide legal services or legal advice. Distribution of
-Creative Commons public licenses does not create a lawyer-client or
-other relationship. Creative Commons makes its licenses and related
-information available on an "as-is" basis. Creative Commons gives no
-warranties regarding its licenses, any material licensed under their
-terms and conditions, or any related information. Creative Commons
-disclaims all liability for damages resulting from their use to the
-fullest extent possible.
-
-Using Creative Commons Public Licenses
-
-Creative Commons public licenses provide a standard set of terms and
-conditions that creators and other rights holders may use to share
-original works of authorship and other material subject to copyright
-and certain other rights specified in the public license below. The
-following considerations are for informational purposes only, are not
-exhaustive, and do not form part of our licenses.
-
-     Considerations for licensors: Our public licenses are
-     intended for use by those authorized to give the public
-     permission to use material in ways otherwise restricted by
-     copyright and certain other rights. Our licenses are
-     irrevocable. Licensors should read and understand the terms
-     and conditions of the license they choose before applying it.
-     Licensors should also secure all rights necessary before
-     applying our licenses so that the public can reuse the
-     material as expected. Licensors should clearly mark any
-     material not subject to the license. This includes other CC-
-     licensed material, or material used under an exception or
-     limitation to copyright. More considerations for licensors:
-	wiki.creativecommons.org/Considerations_for_licensors
-
-     Considerations for the public: By using one of our public
-     licenses, a licensor grants the public permission to use the
-     licensed material under specified terms and conditions. If
-     the licensor's permission is not necessary for any reason--for
-     example, because of any applicable exception or limitation to
-     copyright--then that use is not regulated by the license. Our
-     licenses grant only permissions under copyright and certain
-     other rights that a licensor has authority to grant. Use of
-     the licensed material may still be restricted for other
-     reasons, including because others have copyright or other
-     rights in the material. A licensor may make special requests,
-     such as asking that all changes be marked or described.
-     Although not required by our licenses, you are encouraged to
-     respect those requests where reasonable. More_considerations
-     for the public: 
-	wiki.creativecommons.org/Considerations_for_licensees
-
-=======================================================================
-
-Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
-Public License
-
-By exercising the Licensed Rights (defined below), You accept and agree
-to be bound by the terms and conditions of this Creative Commons
-Attribution-NonCommercial-ShareAlike 4.0 International Public License
-("Public License"). To the extent this Public License may be
-interpreted as a contract, You are granted the Licensed Rights in
-consideration of Your acceptance of these terms and conditions, and the
-Licensor grants You such rights in consideration of benefits the
-Licensor receives from making the Licensed Material available under
-these terms and conditions.
-
-
-Section 1 -- Definitions.
-
-  a. Adapted Material means material subject to Copyright and Similar
-     Rights that is derived from or based upon the Licensed Material
-     and in which the Licensed Material is translated, altered,
-     arranged, transformed, or otherwise modified in a manner requiring
-     permission under the Copyright and Similar Rights held by the
-     Licensor. For purposes of this Public License, where the Licensed
-     Material is a musical work, performance, or sound recording,
-     Adapted Material is always produced where the Licensed Material is
-     synched in timed relation with a moving image.
-
-  b. Adapter's License means the license You apply to Your Copyright
-     and Similar Rights in Your contributions to Adapted Material in
-     accordance with the terms and conditions of this Public License.
-
-  c. BY-NC-SA Compatible License means a license listed at
-     creativecommons.org/compatiblelicenses, approved by Creative
-     Commons as essentially the equivalent of this Public License.
-
-  d. Copyright and Similar Rights means copyright and/or similar rights
-     closely related to copyright including, without limitation,
-     performance, broadcast, sound recording, and Sui Generis Database
-     Rights, without regard to how the rights are labeled or
-     categorized. For purposes of this Public License, the rights
-     specified in Section 2(b)(1)-(2) are not Copyright and Similar
-     Rights.
-
-  e. Effective Technological Measures means those measures that, in the
-     absence of proper authority, may not be circumvented under laws
-     fulfilling obligations under Article 11 of the WIPO Copyright
-     Treaty adopted on December 20, 1996, and/or similar international
-     agreements.
-
-  f. Exceptions and Limitations means fair use, fair dealing, and/or
-     any other exception or limitation to Copyright and Similar Rights
-     that applies to Your use of the Licensed Material.
-
-  g. License Elements means the license attributes listed in the name
-     of a Creative Commons Public License. The License Elements of this
-     Public License are Attribution, NonCommercial, and ShareAlike.
-
-  h. Licensed Material means the artistic or literary work, database,
-     or other material to which the Licensor applied this Public
-     License.
-
-  i. Licensed Rights means the rights granted to You subject to the
-     terms and conditions of this Public License, which are limited to
-     all Copyright and Similar Rights that apply to Your use of the
-     Licensed Material and that the Licensor has authority to license.
-
-  j. Licensor means the individual(s) or entity(ies) granting rights
-     under this Public License.
-
-  k. NonCommercial means not primarily intended for or directed towards
-     commercial advantage or monetary compensation. For purposes of
-     this Public License, the exchange of the Licensed Material for
-     other material subject to Copyright and Similar Rights by digital
-     file-sharing or similar means is NonCommercial provided there is
-     no payment of monetary compensation in connection with the
-     exchange.
-
-  l. Share means to provide material to the public by any means or
-     process that requires permission under the Licensed Rights, such
-     as reproduction, public display, public performance, distribution,
-     dissemination, communication, or importation, and to make material
-     available to the public including in ways that members of the
-     public may access the material from a place and at a time
-     individually chosen by them.
-
-  m. Sui Generis Database Rights means rights other than copyright
-     resulting from Directive 96/9/EC of the European Parliament and of
-     the Council of 11 March 1996 on the legal protection of databases,
-     as amended and/or succeeded, as well as other essentially
-     equivalent rights anywhere in the world.
-
-  n. You means the individual or entity exercising the Licensed Rights
-     under this Public License. Your has a corresponding meaning.
-
-
-Section 2 -- Scope.
-
-  a. License grant.
-
-       1. Subject to the terms and conditions of this Public License,
-          the Licensor hereby grants You a worldwide, royalty-free,
-          non-sublicensable, non-exclusive, irrevocable license to
-          exercise the Licensed Rights in the Licensed Material to:
-
-            a. reproduce and Share the Licensed Material, in whole or
-               in part, for NonCommercial purposes only; and
-
-            b. produce, reproduce, and Share Adapted Material for
-               NonCommercial purposes only.
-
-       2. Exceptions and Limitations. For the avoidance of doubt, where
-          Exceptions and Limitations apply to Your use, this Public
-          License does not apply, and You do not need to comply with
-          its terms and conditions.
-
-       3. Term. The term of this Public License is specified in Section
-          6(a).
-
-       4. Media and formats; technical modifications allowed. The
-          Licensor authorizes You to exercise the Licensed Rights in
-          all media and formats whether now known or hereafter created,
-          and to make technical modifications necessary to do so. The
-          Licensor waives and/or agrees not to assert any right or
-          authority to forbid You from making technical modifications
-          necessary to exercise the Licensed Rights, including
-          technical modifications necessary to circumvent Effective
-          Technological Measures. For purposes of this Public License,
-          simply making modifications authorized by this Section 2(a)
-          (4) never produces Adapted Material.
-
-       5. Downstream recipients.
-
-            a. Offer from the Licensor -- Licensed Material. Every
-               recipient of the Licensed Material automatically
-               receives an offer from the Licensor to exercise the
-               Licensed Rights under the terms and conditions of this
-               Public License.
-
-            b. Additional offer from the Licensor -- Adapted Material.
-               Every recipient of Adapted Material from You
-               automatically receives an offer from the Licensor to
-               exercise the Licensed Rights in the Adapted Material
-               under the conditions of the Adapter's License You apply.
-
-            c. No downstream restrictions. You may not offer or impose
-               any additional or different terms or conditions on, or
-               apply any Effective Technological Measures to, the
-               Licensed Material if doing so restricts exercise of the
-               Licensed Rights by any recipient of the Licensed
-               Material.
-
-       6. No endorsement. Nothing in this Public License constitutes or
-          may be construed as permission to assert or imply that You
-          are, or that Your use of the Licensed Material is, connected
-          with, or sponsored, endorsed, or granted official status by,
-          the Licensor or others designated to receive attribution as
-          provided in Section 3(a)(1)(A)(i).
-
-  b. Other rights.
-
-       1. Moral rights, such as the right of integrity, are not
-          licensed under this Public License, nor are publicity,
-          privacy, and/or other similar personality rights; however, to
-          the extent possible, the Licensor waives and/or agrees not to
-          assert any such rights held by the Licensor to the limited
-          extent necessary to allow You to exercise the Licensed
-          Rights, but not otherwise.
-
-       2. Patent and trademark rights are not licensed under this
-          Public License.
-
-       3. To the extent possible, the Licensor waives any right to
-          collect royalties from You for the exercise of the Licensed
-          Rights, whether directly or through a collecting society
-          under any voluntary or waivable statutory or compulsory
-          licensing scheme. In all other cases the Licensor expressly
-          reserves any right to collect such royalties, including when
-          the Licensed Material is used other than for NonCommercial
-          purposes.
-
-
-Section 3 -- License Conditions.
-
-Your exercise of the Licensed Rights is expressly made subject to the
-following conditions.
-
-  a. Attribution.
-
-       1. If You Share the Licensed Material (including in modified
-          form), You must:
-
-            a. retain the following if it is supplied by the Licensor
-               with the Licensed Material:
-
-                 i. identification of the creator(s) of the Licensed
-                    Material and any others designated to receive
-                    attribution, in any reasonable manner requested by
-                    the Licensor (including by pseudonym if
-                    designated);
-
-                ii. a copyright notice;
-
-               iii. a notice that refers to this Public License;
-
-                iv. a notice that refers to the disclaimer of
-                    warranties;
-
-                 v. a URI or hyperlink to the Licensed Material to the
-                    extent reasonably practicable;
-
-            b. indicate if You modified the Licensed Material and
-               retain an indication of any previous modifications; and
-
-            c. indicate the Licensed Material is licensed under this
-               Public License, and include the text of, or the URI or
-               hyperlink to, this Public License.
-
-       2. You may satisfy the conditions in Section 3(a)(1) in any
-          reasonable manner based on the medium, means, and context in
-          which You Share the Licensed Material. For example, it may be
-          reasonable to satisfy the conditions by providing a URI or
-          hyperlink to a resource that includes the required
-          information.
-       3. If requested by the Licensor, You must remove any of the
-          information required by Section 3(a)(1)(A) to the extent
-          reasonably practicable.
-
-  b. ShareAlike.
-
-     In addition to the conditions in Section 3(a), if You Share
-     Adapted Material You produce, the following conditions also apply.
-
-       1. The Adapter's License You apply must be a Creative Commons
-          license with the same License Elements, this version or
-          later, or a BY-NC-SA Compatible License.
-
-       2. You must include the text of, or the URI or hyperlink to, the
-          Adapter's License You apply. You may satisfy this condition
-          in any reasonable manner based on the medium, means, and
-          context in which You Share Adapted Material.
-
-       3. You may not offer or impose any additional or different terms
-          or conditions on, or apply any Effective Technological
-          Measures to, Adapted Material that restrict exercise of the
-          rights granted under the Adapter's License You apply.
-
-
-Section 4 -- Sui Generis Database Rights.
-
-Where the Licensed Rights include Sui Generis Database Rights that
-apply to Your use of the Licensed Material:
-
-  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
-     to extract, reuse, reproduce, and Share all or a substantial
-     portion of the contents of the database for NonCommercial purposes
-     only;
-
-  b. if You include all or a substantial portion of the database
-     contents in a database in which You have Sui Generis Database
-     Rights, then the database in which You have Sui Generis Database
-     Rights (but not its individual contents) is Adapted Material,
-     including for purposes of Section 3(b); and
-
-  c. You must comply with the conditions in Section 3(a) if You Share
-     all or a substantial portion of the contents of the database.
-
-For the avoidance of doubt, this Section 4 supplements and does not
-replace Your obligations under this Public License where the Licensed
-Rights include other Copyright and Similar Rights.
-
-
-Section 5 -- Disclaimer of Warranties and Limitation of Liability.
-
-  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
-     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
-     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
-     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
-     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
-     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
-     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
-     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
-     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
-     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
-
-  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
-     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
-     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
-     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
-     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
-     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
-     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
-     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
-     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
-
-  c. The disclaimer of warranties and limitation of liability provided
-     above shall be interpreted in a manner that, to the extent
-     possible, most closely approximates an absolute disclaimer and
-     waiver of all liability.
-
-
-Section 6 -- Term and Termination.
-
-  a. This Public License applies for the term of the Copyright and
-     Similar Rights licensed here. However, if You fail to comply with
-     this Public License, then Your rights under this Public License
-     terminate automatically.
-
-  b. Where Your right to use the Licensed Material has terminated under
-     Section 6(a), it reinstates:
-
-       1. automatically as of the date the violation is cured, provided
-          it is cured within 30 days of Your discovery of the
-          violation; or
-
-       2. upon express reinstatement by the Licensor.
-
-     For the avoidance of doubt, this Section 6(b) does not affect any
-     right the Licensor may have to seek remedies for Your violations
-     of this Public License.
-
-  c. For the avoidance of doubt, the Licensor may also offer the
-     Licensed Material under separate terms or conditions or stop
-     distributing the Licensed Material at any time; however, doing so
-     will not terminate this Public License.
-
-  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
-     License.
-
-
-Section 7 -- Other Terms and Conditions.
-
-  a. The Licensor shall not be bound by any additional or different
-     terms or conditions communicated by You unless expressly agreed.
-
-  b. Any arrangements, understandings, or agreements regarding the
-     Licensed Material not stated herein are separate from and
-     independent of the terms and conditions of this Public License.
-
-
-Section 8 -- Interpretation.
-
-  a. For the avoidance of doubt, this Public License does not, and
-     shall not be interpreted to, reduce, limit, restrict, or impose
-     conditions on any use of the Licensed Material that could lawfully
-     be made without permission under this Public License.
-
-  b. To the extent possible, if any provision of this Public License is
-     deemed unenforceable, it shall be automatically reformed to the
-     minimum extent necessary to make it enforceable. If the provision
-     cannot be reformed, it shall be severed from this Public License
-     without affecting the enforceability of the remaining terms and
-     conditions.
-
-  c. No term or condition of this Public License will be waived and no
-     failure to comply consented to unless expressly agreed to by the
-     Licensor.
-
-  d. Nothing in this Public License constitutes or may be interpreted
-     as a limitation upon, or waiver of, any privileges and immunities
-     that apply to the Licensor or You, including from the legal
-     processes of any jurisdiction or authority.
-
-=======================================================================
-
-Creative Commons is not a party to its public licenses.
-Notwithstanding, Creative Commons may elect to apply one of its public
-licenses to material it publishes and in those instances will be
-considered the "Licensor." Except for the limited purpose of indicating
-that material is shared under a Creative Commons public license or as
-otherwise permitted by the Creative Commons policies published at
-creativecommons.org/policies, Creative Commons does not authorize the
-use of the trademark "Creative Commons" or any other trademark or logo
-of Creative Commons without its prior written consent including,
-without limitation, in connection with any unauthorized modifications
-to any of its public licenses or any other arrangements,
-understandings, or agreements concerning use of licensed material. For
-the avoidance of doubt, this paragraph does not form part of the public
-licenses.
-
-Creative Commons may be contacted at creativecommons.org.
-
diff --git a/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml b/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml
index 46d0586..0c0e0ce 100644
--- a/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml
@@ -203,7 +203,7 @@
             If you do decide to use UPDATE_PERIOD_SECONDS, set the interval in the order of minutes.
             A good value might be 600 seconds (10 minutes) if you need updates pulled often.
 
-            Also, remember that this is only a guidance for the system. Android Wear may update less
+            Also, remember that this is only a guidance for the system. Wear may update less
             frequently.
             -->
             <meta-data
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/watchface/AnalogComplicationWatchFaceService.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/watchface/AnalogComplicationWatchFaceService.java
index 2fc0b2d..dfa44f9 100644
--- a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/watchface/AnalogComplicationWatchFaceService.java
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/watchface/AnalogComplicationWatchFaceService.java
@@ -16,9 +16,7 @@
 
 package com.example.android.wearable.watchface.watchface;
 
-import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -31,7 +29,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.support.wearable.complications.ComplicationData;
-import android.support.wearable.complications.ComplicationHelperActivity;
 import android.support.wearable.complications.rendering.ComplicationDrawable;
 import android.support.wearable.watchface.CanvasWatchFaceService;
 import android.support.wearable.watchface.WatchFaceService;
@@ -39,10 +36,8 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.SurfaceHolder;
-
 import com.example.android.wearable.watchface.R;
 import com.example.android.wearable.watchface.config.AnalogComplicationConfigRecyclerViewAdapter;
-
 import java.util.Calendar;
 import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
@@ -231,6 +226,7 @@
             setWatchFaceStyle(
                     new WatchFaceStyle.Builder(AnalogComplicationWatchFaceService.this)
                             .setAcceptsTapEvents(true)
+                            .setHideNotificationIndicator(true)
                             .build());
 
             loadSavedPreferences();
@@ -413,94 +409,25 @@
             Log.d(TAG, "OnTapCommand()");
             switch (tapType) {
                 case TAP_TYPE_TAP:
-                    int tappedComplicationId = getTappedComplicationId(x, y);
-                    if (tappedComplicationId != -1) {
-                        onComplicationTap(tappedComplicationId);
+
+                    // If your background complication is the first item in your array, you need
+                    // to walk backward through the array to make sure the tap isn't for a
+                    // complication above the background complication.
+                    for (int i = COMPLICATION_IDS.length - 1; i >= 0; i--) {
+                        int complicationId = COMPLICATION_IDS[i];
+                        ComplicationDrawable complicationDrawable =
+                                mComplicationDrawableSparseArray.get(complicationId);
+
+                        boolean successfulTap = complicationDrawable.onTap(x, y);
+
+                        if (successfulTap) {
+                            return;
+                        }
                     }
                     break;
             }
         }
 
-        /*
-         * Determines if tap inside a complication area or returns -1.
-         */
-        private int getTappedComplicationId(int x, int y) {
-            int complicationId;
-            ComplicationData complicationData;
-            ComplicationDrawable complicationDrawable;
-
-            long currentTimeMillis = System.currentTimeMillis();
-
-            for (int i = 0; i < COMPLICATION_IDS.length; i++) {
-                complicationId = COMPLICATION_IDS[i];
-                complicationData = mActiveComplicationDataSparseArray.get(complicationId);
-
-                if ((complicationData != null)
-                        && (complicationData.isActive(currentTimeMillis))
-                        // The line below this comment block disables taps for background
-                        // complications (usually not wanted by the user).
-                        // If you do want to enable this, remove the line below and reverse order
-                        // of the loop so it checks the last elements (non-background complications)
-                        // first. Otherwise, the background complication (since it is the size of
-                        // the whole watch face) will capture all taps.
-                        && (complicationData.getType() != ComplicationData.TYPE_LARGE_IMAGE)
-                        && (complicationData.getType() != ComplicationData.TYPE_NOT_CONFIGURED)
-                        && (complicationData.getType() != ComplicationData.TYPE_EMPTY)) {
-
-                    complicationDrawable = mComplicationDrawableSparseArray.get(complicationId);
-                    Rect complicationBoundingRect = complicationDrawable.getBounds();
-
-                    if (complicationBoundingRect.width() > 0) {
-                        if (complicationBoundingRect.contains(x, y)) {
-                            return complicationId;
-                        }
-                    } else {
-                        Log.e(TAG, "Not a recognized complication id.");
-                    }
-                }
-            }
-            return -1;
-        }
-
-        /*
-         * Fires PendingIntent associated with complication (if it has one).
-         */
-        private void onComplicationTap(int complicationId) {
-            Log.d(TAG, "onComplicationTap()");
-
-            ComplicationData complicationData =
-                    mActiveComplicationDataSparseArray.get(complicationId);
-
-            if (complicationData != null) {
-
-                if (complicationData.getTapAction() != null) {
-                    try {
-                        complicationData.getTapAction().send();
-                    } catch (PendingIntent.CanceledException e) {
-                        Log.e(TAG, "On complication tap action error " + e);
-                    }
-
-                } else if (complicationData.getType() == ComplicationData.TYPE_NO_PERMISSION) {
-
-                    // Watch face does not have permission to receive complication data, so launch
-                    // permission request.
-                    ComponentName componentName =
-                            new ComponentName(
-                                    getApplicationContext(),
-                                    AnalogComplicationWatchFaceService.class);
-
-                    Intent permissionRequestIntent =
-                            ComplicationHelperActivity.createPermissionRequestHelperIntent(
-                                    getApplicationContext(), componentName);
-
-                    startActivity(permissionRequestIntent);
-                }
-
-            } else {
-                Log.d(TAG, "No PendingIntent for complication " + complicationId + ".");
-            }
-        }
-
         @Override
         public void onTimeTick() {
             super.onTimeTick();
diff --git a/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.properties
index fe37e6e..1b2e111 100644
--- a/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Mon Mar 27 10:56:30 PDT 2017
+#Fri Nov 03 10:03:20 PDT 2017
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/wearable/wear/WatchFace/template-params.xml b/wearable/wear/WatchFace/template-params.xml
index 5069fd3..fa169b5 100644
--- a/wearable/wear/WatchFace/template-params.xml
+++ b/wearable/wear/WatchFace/template-params.xml
@@ -23,15 +23,18 @@
     <package>com.example.android.wearable.watchface</package>
 
     <minSdk>18</minSdk>
-    <targetSdkVersion>25</targetSdkVersion>
+    <targetSdkVersion>27</targetSdkVersion>
 
     <minSdkVersionWear>24</minSdkVersionWear>
     <compileSdkVersionWear>26</compileSdkVersionWear>
     <targetSdkVersionWear>26</targetSdkVersionWear>
 
-    <dependency>com.google.android.support:wearable:2.0.3</dependency>
-    <dependency_wearable>com.android.support:palette-v7:26.0.0</dependency_wearable>
-    <dependency_wearable>com.android.support:wear:26.0.0</dependency_wearable>
+    <multiDexEnabled>true</multiDexEnabled>
+
+
+    <dependency>com.google.android.support:wearable:2.3.0</dependency>
+    <dependency_wearable>com.android.support:palette-v7:27.1.0</dependency_wearable>
+    <dependency_wearable>com.android.support:wear:27.1.0</dependency_wearable>
 
 
     <wearable>
@@ -41,8 +44,8 @@
     <strings>
         <intro>
 <![CDATA[
-This sample demonstrates how to create watch faces for android wear and use complications with your
-Wear 2.0 watch faces.
+This sample demonstrates how to create watch faces for Wear and use complications
+with your Wear 2.0 watch faces.
 ]]>
         </intro>
     </strings>
@@ -91,7 +94,7 @@
 
         <intro>
 <![CDATA[
-This sample demonstrates how to create watch faces for Android Wear.
+This sample demonstrates how to create watch faces for Wear.
 
 The analog watch face covers best practices for Wear 2.0 including complications and a new
 configuration Activity for configuring both the watch face styles and the complications themselves.
diff --git a/wearable/wear/WatchViewStub/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WatchViewStub/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/WatchViewStub/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/WatchViewStub/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/.gitignore b/wearable/wear/WearAccessibilityApp/.gitignore
new file mode 100644
index 0000000..b90e756
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/.gitignore
@@ -0,0 +1,33 @@
+# built application files
+*.apk
+*.ap_
+
+# files for the dex VM
+*.dex
+
+# Java class files
+*.class
+
+# generated files
+bin/
+gen/
+
+# Ignore gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+proguard-project.txt
+
+# Eclipse files
+.project
+.classpath
+.settings/
+
+# Android Studio/IDEA
+*.iml
+.idea
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/build.gradle b/wearable/wear/WearAccessibilityApp/Wearable/build.gradle
new file mode 100644
index 0000000..a38f216
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/build.gradle
@@ -0,0 +1,80 @@
+
+buildscript {
+    repositories {
+        jcenter()
+        google()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+    }
+}
+
+apply plugin: 'com.android.application'
+
+repositories {
+    jcenter()
+    google()
+}
+
+
+
+dependencies {
+
+    compile 'com.android.support:wear:27.1.0'
+    compile 'com.android.support.constraint:constraint-layout:1.0.2'
+    compile 'com.android.support:appcompat-v7:27.1.0'
+
+
+    compile 'com.google.android.gms:play-services-wearable:11.8.0'
+    compile 'com.android.support:support-v13:27.1.0'
+
+    provided 'com.google.android.wearable:wearable:2.3.0'
+
+    compile 'com.google.android.support:wearable:2.3.0'
+
+}
+
+// The sample build uses multiple directories to
+// keep boilerplate and common code separate from
+// the main sample code.
+List<String> dirs = [
+    'main',     // main sample code; look here for the interesting stuff.
+    'common',   // components that are reused by multiple samples
+    'template'] // boilerplate code that is generated by the sample template process
+
+android {
+
+    compileSdkVersion 26
+
+    buildToolsVersion "27.0.3"
+
+    defaultConfig {
+        versionCode 1
+        versionName "1.0"
+
+        minSdkVersion 24
+
+        targetSdkVersion 26
+
+        multiDexEnabled true
+
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_7
+        targetCompatibility JavaVersion.VERSION_1_7
+    }
+
+    sourceSets {
+        main {
+            dirs.each { dir ->
+                java.srcDirs "src/${dir}/java"
+                res.srcDirs "src/${dir}/res"
+            }
+        }
+        androidTest.setRoot('tests')
+        androidTest.java.srcDirs = ['tests/src']
+
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/AndroidManifest.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..3c7fcaf
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/AndroidManifest.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<manifest package="com.example.android.wearable.wear.wearaccessibilityapp"
+          xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <uses-sdk android:minSdkVersion="14"/>
+
+    <uses-feature android:name="android.hardware.type.watch"/>
+
+    <!-- Required for Always-on. -->
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/launcher_image"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/SampleAppTheme">
+
+        <activity
+            android:label="@string/app_name"
+            android:name=".MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <activity
+            android:label="@string/lists"
+            android:name=".ListsActivity">
+        </activity>
+        <activity
+            android:label="@string/dialogs"
+            android:name=".DialogsActivity">
+        </activity>
+        <activity
+            android:label="@string/progress"
+            android:name=".ProgressActivity">
+        </activity>
+        <activity
+            android:label="@string/controls"
+            android:name=".ControlsActivity">
+        </activity>
+        <activity
+            android:label="@string/notifications"
+            android:name=".NotificationsActivity">
+        </activity>
+        <activity
+            android:label="@string/accessibility"
+            android:name=".AccessibilityActivity">
+        </activity>
+        <activity
+            android:label="@string/a_long_list"
+            android:name=".LongListActivity">
+        </activity>
+        <activity
+            android:label="@string/list_of_graphics"
+            android:name=".ListOfGraphicsActivity">
+        </activity>
+        <activity
+            android:label="@string/photo_carousel"
+            android:name=".PhotoCarouselActivity">
+        </activity>
+        <activity
+            android:label="@string/images"
+            android:name=".ImagesActivity">
+        </activity>
+        <activity
+            android:label="@string/zoom_image"
+            android:name=".ZoomImageActivity">
+        </activity>
+        <activity
+            android:label="@string/open_on_phone_animation"
+            android:name=".OpenOnPhoneAnimationActivity"
+            android:theme="@style/OpenOnPhoneAnimationTheme">
+        </activity>
+        <activity
+            android:label="@string/radio_list"
+            android:name=".RadioListActivity">
+        </activity>
+        <activity
+            android:label="@string/full_screen"
+            android:name=".FullScreenActivity">
+        </activity>
+        <activity
+            android:label="@string/in_line"
+            android:name=".InLineActivity">
+        </activity>
+    </application>
+</manifest>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/AccessibilityActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/AccessibilityActivity.java
new file mode 100644
index 0000000..d982d12
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/AccessibilityActivity.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.wear.ambient.AmbientMode;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class AccessibilityActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_accessibility);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        ImageView accessibilityImage = findViewById(R.id.icon_image_view);
+        accessibilityImage.setImageDrawable(getDrawable(R.drawable.settings_circle));
+
+        TextView accessibilityText = findViewById(R.id.icon_text_view);
+        accessibilityText.setText(R.string.accessibility_settings);
+
+        findViewById(R.id.accessibility_button_include)
+                .setOnClickListener(
+                        new OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+                                startActivityForResult(
+                                        new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0);
+                            }
+                        });
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/AppItem.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/AppItem.java
new file mode 100644
index 0000000..ee1002b
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/AppItem.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+public class AppItem {
+    private final String mItemName;
+    private final int mImageId;
+    private final int mViewType;
+    private final Class mClass;
+
+    public AppItem(String itemName, int imageId, int viewType, Class<? extends Activity> clazz) {
+        mItemName = itemName;
+        mImageId = imageId;
+        mViewType = viewType;
+        mClass = clazz;
+    }
+
+    public AppItem(String itemName, int imageId, Class<? extends Activity> clazz) {
+        mItemName = itemName;
+        mImageId = imageId;
+        mViewType = SampleAppConstants.NORMAL;
+        mClass = clazz;
+    }
+
+    public String getItemName() {
+        return mItemName;
+    }
+
+    public int getImageId() {
+        return mImageId;
+    }
+
+    public int getViewType() {
+        return mViewType;
+    }
+
+    public void launchActivity(Context context) {
+        context.startActivity(new Intent(context, mClass));
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/AppItemListViewAdapter.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/AppItemListViewAdapter.java
new file mode 100644
index 0000000..372f995
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/AppItemListViewAdapter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.List;
+
+public class AppItemListViewAdapter extends ArrayAdapter<AppItem> {
+    private final LayoutInflater mInflater;
+    private List<AppItem> mItems;
+
+    public AppItemListViewAdapter(@NonNull Context context, @NonNull List<AppItem> items) {
+        super(context, R.layout.app_item_layout, items);
+        mInflater = LayoutInflater.from(context);
+        mItems = items;
+    }
+
+    @NonNull
+    @Override
+    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+        Holder holder;
+        if (convertView == null) {
+            convertView = mInflater.inflate(R.layout.shifted_app_item_layout, parent, false);
+            holder = new Holder();
+            holder.mTextView = convertView.findViewById(R.id.shifted_icon_text_view);
+            holder.mImageView = convertView.findViewById(R.id.shifted_icon_image_view);
+            convertView.setTag(holder); // Cache holder for future use.
+        } else {
+            holder = (Holder) convertView.getTag();
+        }
+
+        holder.mTextView.setText(mItems.get(position).getItemName());
+        holder.mImageView.setImageResource(mItems.get(position).getImageId());
+
+        return convertView;
+    }
+
+    private static class Holder {
+        TextView mTextView;
+        ImageView mImageView;
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/CircledImageViewPreference.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/CircledImageViewPreference.java
new file mode 100644
index 0000000..f06ddb8
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/CircledImageViewPreference.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.content.Context;
+import android.os.CountDownTimer;
+import android.preference.Preference;
+import android.support.wearable.view.CircledImageView;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class CircledImageViewPreference extends Preference {
+
+    private CircledImageView mCircledImage;
+    private TextView mCircledImageText;
+    private CountDownTimer mCountDownTimer;
+    private int mColorPrimaryDark;
+    private int mColorAccent;
+    private boolean mIsLoading;
+    private Context mContext;
+
+    public CircledImageViewPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+
+        TypedValue typedValue = new TypedValue();
+        mContext.getTheme().resolveAttribute(android.R.attr.colorPrimaryDark, typedValue, true);
+        mColorPrimaryDark = typedValue.data;
+        mContext.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
+        mColorAccent = typedValue.data;
+    }
+
+    @Override
+    protected View onCreateView(ViewGroup parent) {
+        super.onCreateView(parent);
+        LayoutInflater inflater = LayoutInflater.from(getContext());
+        View circledImageViewLayout = inflater.inflate(R.layout.circled_image_layout, null);
+
+        mCircledImage = circledImageViewLayout.findViewById(R.id.circled_image_view);
+        mCircledImageText = circledImageViewLayout.findViewById(R.id.circled_image_text);
+
+        setStartCircledImageView();
+        return circledImageViewLayout;
+    }
+
+    @Override
+    protected void onClick() {
+        mIsLoading = !mIsLoading;
+        if (mIsLoading) {
+            setLoadingCircledImageView();
+        } else {
+            setStartCircledImageView();
+            cancelCountDownTimer();
+        }
+    }
+
+    public void setStartCircledImageView() {
+        mCircledImageText.setText(R.string.start);
+
+        mCircledImage.setImageResource(R.drawable.start);
+        mCircledImage.setCircleBorderColor(mColorPrimaryDark);
+        mCircledImage.setProgress(1);
+
+        mIsLoading = false;
+    }
+
+    public void setLoadingCircledImageView() {
+        mCircledImageText.setText(R.string.loading);
+        mCircledImage.setImageResource(R.drawable.stop);
+        mCircledImage.setCircleBorderColor(mColorAccent);
+        mCountDownTimer =
+                new CountDownTimer(10000, 10) {
+                    @Override
+                    public void onTick(long millisUntilFinished) {
+                        float timeElapsed = (10000.0f - millisUntilFinished) / 10000.0f;
+                        mCircledImage.setProgress(timeElapsed);
+                    }
+
+                    @Override
+                    public void onFinish() {
+                        setStartCircledImageView();
+                    }
+                }.start();
+    }
+
+    public void cancelCountDownTimer() {
+        if (mCountDownTimer != null) {
+            mCountDownTimer.cancel();
+        }
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ControlsActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ControlsActivity.java
new file mode 100644
index 0000000..40c7a3a
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ControlsActivity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+import android.support.wear.ambient.AmbientMode;
+
+public class ControlsActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Display the fragment as the main content.
+        getFragmentManager()
+                .beginTransaction()
+                .replace(android.R.id.content, new ControlsPrefFragment())
+                .commit();
+    }
+
+    public static class ControlsPrefFragment extends PreferenceFragment {
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            // Load the preferences from an XML resource
+            addPreferencesFromResource(R.xml.prefs_controls);
+        }
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/DialogsActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/DialogsActivity.java
new file mode 100644
index 0000000..cc0d0fb
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/DialogsActivity.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.support.wearable.view.AcceptDenyDialog;
+import android.support.wearable.view.WearableDialogHelper.DialogBuilder;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+public class DialogsActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    private List<DialogsItem> mItems;
+    public View mView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_dialogs);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Supplier objects
+        Supplier<Dialog> twoActionDialog =
+                new Supplier<Dialog>() {
+                    @Override
+                    public Dialog get() {
+                        AcceptDenyDialog twoActionDialog =
+                                new AcceptDenyDialog(DialogsActivity.this);
+                        twoActionDialog.setTitle(R.string.yes_no_dialog);
+                        twoActionDialog.setMessage(getString(R.string.yes_no_dialog_description));
+                        twoActionDialog.setPositiveButton(
+                                new OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+                                        // Add code here for onClick functionality.
+                                    }
+                                });
+                        twoActionDialog.setNegativeButton(
+                                new OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+                                        // Add code here for onClick functionality.
+                                    }
+                                });
+                        return twoActionDialog;
+                    }
+                };
+
+        Supplier<Dialog> oneActionDialog =
+                new Supplier<Dialog>() {
+                    @Override
+                    public Dialog get() {
+                        AcceptDenyDialog oneActionDialog =
+                                new AcceptDenyDialog(DialogsActivity.this);
+                        oneActionDialog.setTitle(R.string.one_action_dialog);
+                        oneActionDialog.setMessage(
+                                getString(R.string.one_action_dialog_description));
+                        oneActionDialog.setPositiveButton(
+                                new OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+                                        // Add code here for onClick functionality.
+                                    }
+                                });
+                        return oneActionDialog;
+                    }
+                };
+
+        Supplier<Dialog> multipleActionDialog =
+                new Supplier<Dialog>() {
+                    @Override
+                    public Dialog get() {
+                        DialogBuilder multipleActionBuilder =
+                                new DialogBuilder(DialogsActivity.this);
+                        multipleActionBuilder.setTitle(R.string.multiple_action_dialog);
+                        multipleActionBuilder.setMessage(
+                                R.string.multiple_action_dialog_description);
+
+                        // OK option.
+                        multipleActionBuilder.setPositiveIcon(R.drawable.accept_circle);
+                        multipleActionBuilder.setPositiveButton(
+                                R.string.ok,
+                                new OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+                                        // Add code here for onClick functionality.
+                                    }
+                                });
+
+                        // Close option.
+                        multipleActionBuilder.setNeutralIcon(R.drawable.deny_circle);
+                        multipleActionBuilder.setNeutralButton(
+                                R.string.close,
+                                new OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+                                        // Add code here for onClick functionality.
+                                    }
+                                });
+
+                        // Open in phone option.
+                        multipleActionBuilder.setNegativeIcon(R.drawable.open_in_phone_circle);
+                        multipleActionBuilder.setNegativeButton(
+                                R.string.open_on_phone,
+                                new OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+                                        Intent intent =
+                                                new Intent(
+                                                        DialogsActivity.this,
+                                                        OpenOnPhoneAnimationActivity.class);
+                                        startActivity(intent);
+                                    }
+                                });
+                        return multipleActionBuilder.create();
+                    }
+                };
+
+        // Create a list of items for adapter to display.
+        mItems = new ArrayList<>();
+        mItems.add(new DialogsItem(R.string.yes_no_action, twoActionDialog));
+        mItems.add(new DialogsItem(R.string.one_action, oneActionDialog));
+        mItems.add(new DialogsItem(R.string.multiple_actions, multipleActionDialog));
+
+        // Initialize an adapter and set it to ListView mListView.
+        ListViewAdapter adapter = new ListViewAdapter(this, mItems);
+        final ListView listView = findViewById(R.id.list_view_dialogs);
+        listView.setAdapter(adapter);
+
+        // Set header of mListView to be the title from title_layout.
+        LayoutInflater inflater = LayoutInflater.from(this);
+        View titleLayout = inflater.inflate(R.layout.title_layout, null);
+        TextView titleView = titleLayout.findViewById(R.id.title_text);
+        titleView.setText(R.string.dialogs);
+        titleView.setOnClickListener(null); // make title non-clickable (will not turn grey)
+
+        listView.addHeaderView(titleView);
+
+        // Goes to a dialog when you click on one of the list items.
+        // Dependent upon position of click.
+        // Note: Keep in mind that icons will not appear on dialog unless you
+        //       set an onClickListener.
+        listView.setOnItemClickListener(
+                new AdapterView.OnItemClickListener() {
+                    @Override
+                    public void onItemClick(
+                            AdapterView<?> parent, View view, int position, long id) {
+                        mView = view;
+                        Dialog dialog =
+                                mItems.get(position - listView.getHeaderViewsCount())
+                                        .getSupplier()
+                                        .get();
+                        dialog.show();
+                    }
+                });
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/DialogsItem.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/DialogsItem.java
new file mode 100644
index 0000000..25e83c3
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/DialogsItem.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Dialog;
+
+import java.util.function.Supplier;
+
+public class DialogsItem implements Item {
+    private final int mItemId;
+    private final Supplier<Dialog> mSupplier;
+
+    public DialogsItem(int itemId, Supplier<Dialog> supplier) {
+        mItemId = itemId;
+        mSupplier = supplier;
+    }
+
+    public int getItemId() {
+        return mItemId;
+    }
+
+    public Supplier<Dialog> getSupplier() {
+        return mSupplier;
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/FullScreenActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/FullScreenActivity.java
new file mode 100644
index 0000000..0145288
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/FullScreenActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+
+public class FullScreenActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        setContentView(R.layout.activity_fullscreen_progress);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/GlobalNotificationBuilder.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/GlobalNotificationBuilder.java
new file mode 100644
index 0000000..812ed94
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/GlobalNotificationBuilder.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.support.v4.app.NotificationCompat;
+
+/**
+ * We use a Singleton for a global copy of the NotificationCompat.Builder to update active
+ * Notifications from other Services/Activities.
+ *
+ * <p>You have two options for updating your notifications:
+ *
+ * <p>1. Use a new NotificationCompatBuilder to create the Notification. This approach requires you
+ * to get *ALL* the information and pass it to the builder. We get all the information from a Mock
+ * Database and this is the approach used in the MainActivity.
+ *
+ * <p>2. Use an existing NotificationCompatBuilder to create a Notification. This approach requires
+ * you to store a reference to the original builder. The benefit is you only need the new/updated
+ * information for an existing notification. We use this approach in the IntentService handlers to
+ * update existing notifications.
+ *
+ * <p>IMPORTANT NOTE 1: You shouldn't save/modify the resulting Notification object using its member
+ * variables and/or legacy APIs. If you want to retain anything from update to update, retain the
+ * Builder as option 2 outlines.
+ *
+ * <p>IMPORTANT NOTE 2: If the global Notification Builder is lost because the process is killed,
+ * you should have a way to recreate the Notification Builder from a persistent state. (We do this
+ * as well in the sample, check the IntentServices.)
+ */
+public final class GlobalNotificationBuilder {
+
+    private static NotificationCompat.Builder sGlobalNotificationCompatBuilder = null;
+
+    /*
+     * Empty constructor - We don't initialize builder because we rely on a null state to let us
+     * know the Application's process was killed.
+     */
+    private GlobalNotificationBuilder() {}
+
+    public static void setNotificationCompatBuilderInstance(NotificationCompat.Builder builder) {
+        sGlobalNotificationCompatBuilder = builder;
+    }
+
+    public static NotificationCompat.Builder getNotificationCompatBuilderInstance() {
+        return sGlobalNotificationCompatBuilder;
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ImagesActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ImagesActivity.java
new file mode 100644
index 0000000..2291fbc
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ImagesActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.graphics.drawable.Animatable2.AnimationCallback;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.widget.ImageView;
+
+public class ImagesActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+    private AnimatedVectorDrawable mAnimatedVectorDrawableSwipe;
+    private AnimatedVectorDrawable mAnimatedVectorDrawableTap;
+    private AnimationCallback mAnimationCallback;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_images);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Used to repeat animation from the beginning.
+        mAnimationCallback =
+                new AnimationCallback() {
+                    @Override
+                    public void onAnimationEnd(Drawable drawable) {
+                        super.onAnimationEnd(drawable);
+                        ((AnimatedVectorDrawable) drawable).start();
+                    }
+                };
+
+        // Play 'swipe left' animation on loop.
+        ImageView mSwipeLeftImage = findViewById(R.id.swipe_left_image);
+        mAnimatedVectorDrawableSwipe = (AnimatedVectorDrawable) mSwipeLeftImage.getDrawable();
+        mAnimatedVectorDrawableSwipe.start();
+        mAnimatedVectorDrawableSwipe.registerAnimationCallback(mAnimationCallback);
+
+        // Play 'tap' animation on loop.
+        ImageView mTapImage = findViewById(R.id.tap_image);
+        mAnimatedVectorDrawableTap = (AnimatedVectorDrawable) mTapImage.getDrawable();
+        mAnimatedVectorDrawableTap.start();
+        mAnimatedVectorDrawableTap.registerAnimationCallback(mAnimationCallback);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mAnimatedVectorDrawableSwipe.unregisterAnimationCallback(mAnimationCallback);
+        mAnimatedVectorDrawableTap.unregisterAnimationCallback(mAnimationCallback);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/InLineActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/InLineActivity.java
new file mode 100644
index 0000000..723d57c
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/InLineActivity.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.support.wear.ambient.AmbientMode;
+
+public class InLineActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        getFragmentManager()
+                .beginTransaction()
+                .replace(android.R.id.content, new InLinePrefFragment())
+                .commit();
+    }
+
+    public static class InLinePrefFragment extends PreferenceFragment {
+
+        private SwitchPreference mDeterminantSwitchPref;
+        private CircledImageViewPreference mCircledImageViewPref;
+        private ProgressBarPreference mProgressBarPreference;
+        private PreferenceScreen mPreferenceScreen;
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            // Load the preferences from an XML resource
+            addPreferencesFromResource(R.xml.prefs_in_line_progress);
+
+            mDeterminantSwitchPref =
+                    (SwitchPreference)
+                            findPreference(getString(R.string.key_pref_determinant_switch));
+            mDeterminantSwitchPref.setChecked(true);
+
+            mCircledImageViewPref =
+                    (CircledImageViewPreference)
+                            findPreference(getString(R.string.key_pref_circled_image_view));
+
+            mPreferenceScreen =
+                    (PreferenceScreen) findPreference(getString(R.string.key_pref_progress_screen));
+
+            mProgressBarPreference = new ProgressBarPreference(getContext());
+            mProgressBarPreference.setTitle("@string/indeterminant_progress");
+
+            mDeterminantSwitchPref.setOnPreferenceChangeListener(
+                    new OnPreferenceChangeListener() {
+                        @Override
+                        public boolean onPreferenceChange(Preference preference, Object newValue) {
+                            mDeterminantSwitchPref.setChecked(!mDeterminantSwitchPref.isChecked());
+                            if (mDeterminantSwitchPref.isChecked()) {
+                                mCircledImageViewPref.cancelCountDownTimer();
+                                mCircledImageViewPref.setStartCircledImageView();
+                                mPreferenceScreen.removePreference(mProgressBarPreference);
+                                mPreferenceScreen.addPreference(mCircledImageViewPref);
+                            } else {
+                                mPreferenceScreen.removePreference(mCircledImageViewPref);
+                                mPreferenceScreen.addPreference(mProgressBarPreference);
+                            }
+                            return true;
+                        }
+                    });
+        }
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/Item.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/Item.java
new file mode 100644
index 0000000..182340e
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/Item.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+public interface Item {
+    int getItemId();
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListOfGraphicsActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListOfGraphicsActivity.java
new file mode 100644
index 0000000..1159ebc
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListOfGraphicsActivity.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ListOfGraphicsActivity extends Activity
+        implements AmbientMode.AmbientCallbackProvider {
+    private List<AppItem> mItems;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_list_of_graphics);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Store all data in a list for adapter to use.
+        mItems = new ArrayList<AppItem>();
+        mItems.add(
+                new AppItem(
+                        getString(R.string.photo_carousel),
+                        R.drawable.heart_circle,
+                        SampleAppConstants.NORMAL,
+                        PhotoCarouselActivity.class));
+        mItems.add(
+                new AppItem(
+                        getString(R.string.images),
+                        R.drawable.heart_circle,
+                        SampleAppConstants.NORMAL,
+                        ImagesActivity.class));
+
+        // Set up an adapter and pass in all the items you initialized above.
+        AppItemListViewAdapter adapter = new AppItemListViewAdapter(this, mItems);
+        final ListView listView = findViewById(R.id.list_view_graphics);
+        listView.setAdapter(adapter);
+
+        // Set header of list view to be a title.
+        LayoutInflater inflater = LayoutInflater.from(this);
+        View titleLayout = inflater.inflate(R.layout.title_layout, null);
+        TextView titleView = titleLayout.findViewById(R.id.title_text);
+        titleView.setText(R.string.list_of_graphics); // Set the text of the title.
+        listView.addHeaderView(titleView, getString(R.string.title), false); // Set header.
+
+        // Goes to a new screen when you click on one of the list items.
+        // Dependent upon position of click.
+        listView.setOnItemClickListener(
+                new AdapterView.OnItemClickListener() {
+                    @Override
+                    public void onItemClick(
+                            AdapterView<?> parent, View view, int position, long id) {
+                        mItems.get(position - listView.getHeaderViewsCount())
+                                .launchActivity(getApplicationContext());
+                    }
+                });
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListViewAdapter.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListViewAdapter.java
new file mode 100644
index 0000000..41b18d8
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListViewAdapter.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.List;
+
+public class ListViewAdapter<T extends Item> extends ArrayAdapter<T> {
+    private final LayoutInflater mInflater;
+    private List<T> mItems;
+
+    public ListViewAdapter(@NonNull Context context, @NonNull List<T> items) {
+        super(context, R.layout.list_item_layout, items);
+        mInflater = LayoutInflater.from(context);
+        mItems = items;
+    }
+
+    @NonNull
+    @Override
+    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+        Holder holder;
+        if (convertView == null) {
+            convertView = mInflater.inflate(R.layout.list_item_layout, parent, false);
+            holder = new Holder();
+            holder.mTextView = convertView.findViewById(R.id.item_text);
+            holder.mImageView = convertView.findViewById(R.id.item_image);
+            convertView.setTag(holder); // Cache the holder for future use.
+        } else {
+            holder = (Holder) convertView.getTag();
+        }
+        holder.mTextView.setText(mItems.get(position).getItemId());
+        return convertView;
+    }
+
+    private static class Holder {
+        TextView mTextView;
+        ImageView mImageView;
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListsActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListsActivity.java
new file mode 100644
index 0000000..0ef82dc
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListsActivity.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ListsActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+    private List<ListsItem> mItems;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_lists);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Create a list of items for adapter to display.
+        mItems = new ArrayList<>();
+        mItems.add(new ListsItem(R.string.a_long_list, LongListActivity.class));
+        mItems.add(new ListsItem(R.string.list_of_graphics, ListOfGraphicsActivity.class));
+
+        // Initialize an adapter and set it to ListView listView.
+        ListViewAdapter adapter = new ListViewAdapter(this, mItems);
+        final ListView listView = findViewById(R.id.list_view_lists);
+        listView.setAdapter(adapter);
+
+        // Set header of listView to be the title from title_layout.
+        LayoutInflater inflater = LayoutInflater.from(this);
+        View titleLayout = inflater.inflate(R.layout.title_layout, null);
+        TextView titleView = titleLayout.findViewById(R.id.title_text);
+        titleView.setText(R.string.lists);
+        titleView.setOnClickListener(null); // make title non-clickable.
+
+        listView.addHeaderView(titleView);
+
+        // Goes to a new screen when you click on one of the list items.
+        // Dependent upon position of click.
+        listView.setOnItemClickListener(
+                new AdapterView.OnItemClickListener() {
+                    @Override
+                    public void onItemClick(
+                            AdapterView<?> parent, View view, int position, long id) {
+                        mItems.get(position - listView.getHeaderViewsCount())
+                                .launchActivity(getApplicationContext());
+                    }
+                });
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListsItem.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListsItem.java
new file mode 100644
index 0000000..42e8464
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ListsItem.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+public class ListsItem implements Item {
+    private final int mItemId;
+    private final Class mClass;
+
+    public ListsItem(int itemId, Class<? extends Activity> clazz) {
+        mItemId = itemId;
+        mClass = clazz;
+    }
+
+    public int getItemId() {
+        return mItemId;
+    }
+
+    public void launchActivity(Context context) {
+        context.startActivity(new Intent(context, mClass));
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/LongListActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/LongListActivity.java
new file mode 100644
index 0000000..b2fd721
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/LongListActivity.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.wear.ambient.AmbientMode;
+import android.support.wear.widget.WearableRecyclerView;
+import android.support.wear.widget.drawer.WearableActionDrawerView;
+import android.view.View;
+
+import com.example.android.wearable.wear.wearaccessibilityapp.LongListRecyclerViewAdapter.SwitchChangeListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LongListActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    private List<AppItem> mItems;
+    private LongListRecyclerViewAdapter mAdapter;
+    private Handler mHandler;
+    private int mPreviousLastVisibleItem;
+    private int mLastVisibleItem;
+    private boolean mFinishLoad;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_long_list);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        mHandler = new Handler();
+
+        // List of items to display within recyclerView (used by adapter).
+        mItems = new ArrayList<AppItem>();
+        mItems.add(new AppItem(null, 0, SampleAppConstants.TITLE, null)); // for title
+        mItems.add(new AppItem(null, 0, SampleAppConstants.SWITCH, null)); // for switch widget
+        for (int i = 1; i <= 10; i++) {
+            mItems.add(
+                    new AppItem(
+                            getResources().getString(R.string.item_text, i),
+                            R.drawable.heart_circle,
+                            SampleAppConstants.NORMAL,
+                            null));
+        }
+
+        // Custom adapter used so we can use custom layout for the rows within the list.
+        mAdapter =
+                new LongListRecyclerViewAdapter(
+                        this,
+                        mItems,
+                        new SwitchChangeListener() {
+                            @Override
+                            public void onChange(boolean switchOn) {
+                                WearableActionDrawerView wearableActionDrawer =
+                                        findViewById(R.id.action_drawer_long_list);
+
+                                if (switchOn) {
+                                    wearableActionDrawer.setVisibility(
+                                            View.VISIBLE); // Hide drawer.
+                                } else {
+                                    wearableActionDrawer.setVisibility(
+                                            View.INVISIBLE); // Hide drawer.
+                                }
+                            }
+                        });
+        WearableRecyclerView recyclerView = findViewById(R.id.recycler_view_long_list);
+
+        recyclerView.setLayoutManager(new LinearLayoutManager(this));
+        recyclerView.setHasFixedSize(false);
+
+        recyclerView.setAdapter(mAdapter); // Set adapter to the recyclerView.
+
+        // Uncomment if you want the action drawer to show while scrolling down.
+        // WearableActionDrawer mWearableActionDrawer=
+        //         (WearableActionDrawer) findViewById(R.id.action_drawer_long_list);
+        // mWearableActionDrawer.setShouldPeekOnScrollDown(true);
+
+        mPreviousLastVisibleItem = 0; // default
+        mLastVisibleItem = 0;
+        mFinishLoad = false;
+
+        if (!(recyclerView.getLayoutManager() instanceof LinearLayoutManager)) {
+            return; // invalid layout manager
+        }
+
+        final LinearLayoutManager layoutManager =
+                (LinearLayoutManager) recyclerView.getLayoutManager();
+
+        recyclerView.addOnScrollListener(
+                new WearableRecyclerView.OnScrollListener() {
+                    @Override
+                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                        super.onScrolled(recyclerView, dx, dy);
+                        mLastVisibleItem = layoutManager.findLastVisibleItemPosition();
+                        if (!mFinishLoad) {
+                            int count =
+                                    layoutManager
+                                            .getItemCount(); // total items in the recycler view
+
+                            // Do not notify LongListActivity if no NEW items have been displayed.
+                            if (mLastVisibleItem <= mPreviousLastVisibleItem) {
+                                return;
+                            }
+
+                            // Do not notify LongListActivity if not yet scrolled to threshold.
+                            if (mLastVisibleItem < count - 1) {
+                                return;
+                            }
+
+                            if (mLastVisibleItem % 10 == 2 && mLastVisibleItem != 2) {
+                                return;
+                            }
+
+                            // End of list, no more loading.
+                            if (mLastVisibleItem >= SampleAppConstants.END_OF_LONG_LIST) {
+                                mFinishLoad = true; // we are done loading more items.
+                                addFooter();
+                                return;
+                            }
+
+                            // Load more items
+                            addData();
+
+                            // To check if new items should be displayed or not.
+                            mPreviousLastVisibleItem = mLastVisibleItem;
+                        }
+                    }
+                });
+    }
+
+    /**
+     * Add items to List<AppItem> items. More items requested by adapter (used to load list in
+     * batches of 10).
+     */
+    public void addData() {
+        // Add progress bar to list.
+        mItems.add(new AppItem(null, 0, SampleAppConstants.PROGRESS_BAR, null));
+        mAdapter.notifyItemInserted(mItems.size() - 1);
+
+        // Delay for 1000 milliseconds and then execute below code.
+        mHandler.postDelayed(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        // Remove progress after the delay.
+                        mItems.remove(mItems.size() - 1);
+
+                        // Add ten items to List<AppItem> items.
+                        int listSize = mItems.size();
+                        for (int i = listSize - 1; i <= listSize + 8; i++) {
+                            mItems.add(
+                                    new AppItem(
+                                            getResources().getString(R.string.item_text, i),
+                                            R.drawable.heart_circle,
+                                            SampleAppConstants.NORMAL,
+                                            null));
+                        }
+                        mAdapter.notifyDataSetChanged();
+                    }
+                },
+                1000);
+    }
+
+    /** Add footer to List<AppItem> items. Requested by adapter (called at the end of the list). */
+    public void addFooter() {
+        mItems.add(new AppItem(null, 0, SampleAppConstants.HEADER_FOOTER, null)); // add footer
+        mAdapter.notifyItemInserted(mItems.size() - 1);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/LongListRecyclerViewAdapter.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/LongListRecyclerViewAdapter.java
new file mode 100644
index 0000000..96b273a
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/LongListRecyclerViewAdapter.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import java.util.List;
+
+public class LongListRecyclerViewAdapter
+        extends RecyclerView.Adapter<LongListRecyclerViewAdapter.Holder> {
+
+    // For custom listener.
+    public interface SwitchChangeListener {
+
+        void onChange(boolean switchOn);
+    }
+
+    private final LayoutInflater mInflater;
+    private List<AppItem> mItems;
+    private SwitchChangeListener mSwitchChangeListener;
+    private Switch mSwitchWidget;
+    private Context mContext;
+
+    public LongListRecyclerViewAdapter(
+            Context context, List<AppItem> items, SwitchChangeListener switchChangeListener) {
+        mContext = context;
+        mItems = items;
+        mInflater = LayoutInflater.from(context);
+
+        // Forces activity to implement a SwitchChangeListener
+        mSwitchChangeListener = switchChangeListener;
+    }
+
+    @Override
+    public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
+        final View view;
+        switch (viewType) {
+            case SampleAppConstants.TITLE:
+                // Programmatically set the text of the title here.
+                view = mInflater.inflate(R.layout.title_layout, parent, false);
+                TextView titleView = view.findViewById(R.id.title_text);
+                titleView.setText(R.string.a_long_list);
+                break;
+            case SampleAppConstants.SWITCH:
+                // Reference the switch widget's text and view.
+                view = mInflater.inflate(R.layout.long_list_switch_widget_layout, parent, false);
+                TextView switchText = view.findViewById(R.id.switch_text);
+                switchText.setText(R.string.bottom_action_drawer);
+
+                mSwitchWidget = view.findViewById(R.id.switch_widget);
+
+                view.setContentDescription(
+                        mContext.getResources()
+                                .getString(
+                                        R.string.switch_bottom_action_drawer,
+                                        getSwitchToggleString(mSwitchWidget.isChecked())));
+
+                // Set the OnClickListener (Observer pattern used here).
+                view.setOnClickListener(
+                        new OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+                                mSwitchWidget.setChecked(!(mSwitchWidget.isChecked()));
+                                if (mSwitchChangeListener != null) {
+                                    mSwitchChangeListener.onChange(mSwitchWidget.isChecked());
+                                }
+                                view.setContentDescription(
+                                        mContext.getResources()
+                                                .getString(
+                                                        R.string.switch_bottom_action_drawer,
+                                                        getSwitchToggleString(
+                                                                mSwitchWidget.isChecked())));
+                            }
+                        });
+                break;
+            case SampleAppConstants.HEADER_FOOTER:
+                view = mInflater.inflate(R.layout.header_footer_layout, parent, false);
+                break;
+            case SampleAppConstants.PROGRESS_BAR:
+                view = mInflater.inflate(R.layout.progress_bar_layout, parent, false);
+                break;
+            case SampleAppConstants.NORMAL:
+                view = mInflater.inflate(R.layout.shifted_app_item_layout, parent, false);
+                break;
+            default:
+                view = mInflater.inflate(R.layout.shifted_app_item_layout, parent, false);
+                break;
+        }
+        return new Holder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(Holder holder, int position) {
+        if (mItems.isEmpty()) {
+            return;
+        }
+
+        AppItem item = mItems.get(position);
+        int itemViewType = item.getViewType();
+
+        // Return - Don't want to bind AppItem item info because item is null.
+        if (itemViewType != SampleAppConstants.NORMAL) {
+            return;
+        }
+
+        holder.bind(item);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mItems.size();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return mItems.get(position).getViewType();
+    }
+
+    /**
+     * Used to set Switch widget's content description dynamically.
+     *
+     * @param isChecked
+     * @return "on" if true, "off" otherwise
+     */
+    public String getSwitchToggleString(boolean isChecked) {
+        return isChecked ? mContext.getString(R.string.on) : mContext.getString(R.string.off);
+    }
+
+    // class-specific ViewHolder
+    static class Holder extends ViewHolder {
+        TextView mTextView;
+        ImageView mImageView;
+
+        public Holder(final View itemView) {
+            super(itemView);
+            mTextView = itemView.findViewById(R.id.shifted_icon_text_view);
+            mImageView = itemView.findViewById(R.id.shifted_icon_image_view);
+        }
+
+        /** Bind appItem info to main screen (displays the item). */
+        public void bind(AppItem item) {
+            mTextView.setText(item.getItemName());
+            mImageView.setImageResource(item.getImageId());
+        }
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MainActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MainActivity.java
new file mode 100644
index 0000000..a1f1d37
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MainActivity.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.support.wear.widget.WearableLinearLayoutManager;
+import android.support.wear.widget.WearableRecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MainActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Menu items
+        List<AppItem> items = new ArrayList<AppItem>();
+        items.add(
+                new AppItem(
+                        getString(R.string.lists), R.drawable.lists_circle, ListsActivity.class));
+        items.add(
+                new AppItem(
+                        getString(R.string.dialogs),
+                        R.drawable.dialogs_circle,
+                        DialogsActivity.class));
+        items.add(
+                new AppItem(
+                        getString(R.string.progress),
+                        R.drawable.progress_circle,
+                        ProgressActivity.class));
+        items.add(
+                new AppItem(
+                        getString(R.string.controls),
+                        R.drawable.controls_circle,
+                        ControlsActivity.class));
+        items.add(
+                new AppItem(
+                        getString(R.string.notifications),
+                        R.drawable.notifications_circle,
+                        NotificationsActivity.class));
+        items.add(
+                new AppItem(
+                        getString(R.string.accessibility),
+                        R.drawable.accessibility_circle,
+                        AccessibilityActivity.class));
+
+        MenuRecyclerViewAdapter appListAdapter = new MenuRecyclerViewAdapter(this, items);
+
+        WearableRecyclerView recyclerView = findViewById(R.id.main_recycler_view);
+
+        // Customizes scrolling so items farther away form center are smaller.
+        ScalingScrollLayoutCallback scalingScrollLayoutCallback = new ScalingScrollLayoutCallback();
+        recyclerView.setLayoutManager(
+                new WearableLinearLayoutManager(this, scalingScrollLayoutCallback));
+
+        recyclerView.setEdgeItemsCenteringEnabled(true);
+        recyclerView.setAdapter(appListAdapter);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MenuRecyclerViewAdapter.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MenuRecyclerViewAdapter.java
new file mode 100644
index 0000000..e536762
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MenuRecyclerViewAdapter.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.List;
+
+public class MenuRecyclerViewAdapter extends RecyclerView.Adapter<MenuRecyclerViewAdapter.Holder> {
+
+    private final Context mContext;
+    private final LayoutInflater mInflater;
+    private List<AppItem> mItems;
+
+    public MenuRecyclerViewAdapter(Context context, List<AppItem> items) {
+        this.mContext = context;
+        this.mItems = items;
+        mInflater = LayoutInflater.from(context);
+    }
+
+    @Override
+    public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
+        /* Add check for viewType here if used.
+        See LongListRecyclerViewAdapter for an example. */
+
+        return new Holder(mInflater.inflate(R.layout.app_item_layout, parent, false));
+    }
+
+    @Override
+    public void onBindViewHolder(Holder holder, int position) {
+        if (mItems.isEmpty()) {
+            return;
+        }
+        final AppItem item = mItems.get(position);
+
+        if (item.getViewType() == SampleAppConstants.HEADER_FOOTER) {
+            return;
+        }
+
+        holder.bind(item);
+
+        // Start new activity on click of specific item.
+        final int pos = position;
+        holder.itemView.setOnClickListener(
+                new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        mItems.get(pos).launchActivity(mContext);
+                    }
+                });
+    }
+
+    @Override
+    public int getItemCount() {
+        return mItems.size();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return mItems.get(position).getViewType();
+    }
+
+    static class Holder extends ViewHolder {
+        TextView mTextView;
+        ImageView mImageView;
+
+        public Holder(final View itemView) {
+            super(itemView);
+            mTextView = itemView.findViewById(R.id.icon_text_view);
+            mImageView = itemView.findViewById(R.id.icon_image_view);
+        }
+
+        /** Bind appItem info to main screen (displays the item). */
+        public void bind(AppItem item) {
+            mTextView.setText(item.getItemName());
+            mImageView.setImageResource(item.getImageId());
+        }
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MessagingIntentService.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MessagingIntentService.java
new file mode 100644
index 0000000..b8e998f
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MessagingIntentService.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.IntentService;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationCompat.MessagingStyle;
+import android.support.v4.app.NotificationManagerCompat;
+import android.support.v4.app.RemoteInput;
+import android.util.Log;
+
+/**
+ * Asynchronously handles updating messaging app posts (and active Notification) with replies from
+ * user in a conversation. Notification for social app use MessagingStyle.
+ */
+public class MessagingIntentService extends IntentService {
+
+    private static final String TAG = "MessagingIntentService";
+
+    public static final String ACTION_REPLY =
+            "com.example.android.wearable.wear.wearnotifications.handlers.action.REPLY";
+
+    public static final String EXTRA_REPLY =
+            "com.example.android.wearable.wear.wearnotifications.handlers.extra.REPLY";
+
+    public MessagingIntentService() {
+        super("MessagingIntentService");
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        Log.d(TAG, "onHandleIntent(): " + intent);
+
+        if (intent != null) {
+            final String action = intent.getAction();
+            if (ACTION_REPLY.equals(action)) {
+                handleActionReply(getMessage(intent));
+            }
+        }
+    }
+
+    /** Handles action for replying to messages from the notification. */
+    private void handleActionReply(CharSequence replyCharSequence) {
+        Log.d(TAG, "handleActionReply(): " + replyCharSequence);
+
+        if (replyCharSequence != null) {
+
+            // TODO: Asynchronously save your message to Database and servers.
+
+            /*
+             * You have two options for updating your notification (this class uses approach #2):
+             *
+             *  1. Use a new NotificationCompatBuilder to create the Notification. This approach
+             *  requires you to get *ALL* the information that existed in the previous
+             *  Notification (and updates) and pass it to the builder. This is the approach used in
+             *  the MainActivity.
+             *
+             *  2. Use the original NotificationCompatBuilder to create the Notification. This
+             *  approach requires you to store a reference to the original builder. The benefit is
+             *  you only need the new/updated information. In our case, the reply from the user
+             *  which we already have here.
+             *
+             *  IMPORTANT NOTE: You shouldn't save/modify the resulting Notification object using
+             *  its member variables and/or legacy APIs. If you want to retain anything from update
+             *  to update, retain the Builder as option 2 outlines.
+             */
+
+            // Retrieves NotificationCompat.Builder used to create initial Notification
+            NotificationCompat.Builder notificationCompatBuilder =
+                    GlobalNotificationBuilder.getNotificationCompatBuilderInstance();
+
+            // Recreate builder from persistent state if app process is killed
+            if (notificationCompatBuilder == null) {
+                // Note: New builder set globally in the method
+                notificationCompatBuilder = recreateBuilderWithMessagingStyle();
+            }
+
+            // Since we are adding to the MessagingStyle, we need to first retrieve the
+            // current MessagingStyle from the Notification itself.
+            Notification notification = notificationCompatBuilder.build();
+            MessagingStyle messagingStyle =
+                    NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(
+                            notification);
+
+            // Add new message to the MessagingStyle
+            messagingStyle.addMessage(replyCharSequence, System.currentTimeMillis(), null);
+
+            // Updates the Notification
+            notification = notificationCompatBuilder.setStyle(messagingStyle).build();
+
+            // Pushes out the updated Notification
+            NotificationManagerCompat notificationManagerCompat =
+                    NotificationManagerCompat.from(getApplicationContext());
+            notificationManagerCompat.notify(NotificationsActivity.NOTIFICATION_ID, notification);
+        }
+    }
+
+    /*
+     * Extracts CharSequence created from the RemoteInput associated with the Notification.
+     */
+    private CharSequence getMessage(Intent intent) {
+        Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
+        if (remoteInput != null) {
+            return remoteInput.getCharSequence(EXTRA_REPLY);
+        }
+        return null;
+    }
+
+    /*
+     * This recreates the notification from the persistent state in case the app process was killed.
+     * It is basically the same code for creating the Notification from MainActivity.
+     */
+    private NotificationCompat.Builder recreateBuilderWithMessagingStyle() {
+
+        // Main steps for building a MESSAGING_STYLE notification (for more detailed comments on
+        // building this notification, check StandaloneMainActivity.java)::
+        //      0. Get your data
+        //      1. Build the MESSAGING_STYLE
+        //      2. Add support for Wear 1.+
+        //      3. Set up main Intent for notification
+        //      4. Set up RemoteInput (users can input directly from notification)
+        //      5. Build and issue the notification
+
+        // 0. Get your data (everything unique per Notification)
+        MockDatabase.MessagingStyleCommsAppData messagingStyleCommsAppData =
+                MockDatabase.getMessagingStyleData();
+
+        // 1. Build the Notification.Style (MESSAGING_STYLE)
+        String contentTitle = messagingStyleCommsAppData.getContentTitle();
+
+        MessagingStyle messagingStyle =
+                new NotificationCompat.MessagingStyle(messagingStyleCommsAppData.getReplayName())
+                        .setConversationTitle(contentTitle);
+
+        // Adds all Messages
+        for (MessagingStyle.Message message : messagingStyleCommsAppData.getMessages()) {
+            messagingStyle.addMessage(message);
+        }
+
+        // 2. Add support for Wear 1.+.
+        String fullMessageForWearVersion1 = messagingStyleCommsAppData.getFullConversation();
+
+        Notification chatHistoryForWearV1 =
+                new NotificationCompat.Builder(getApplicationContext())
+                        .setStyle(
+                                new NotificationCompat.BigTextStyle()
+                                        .bigText(fullMessageForWearVersion1))
+                        .setContentTitle(contentTitle)
+                        .setSmallIcon(R.drawable.watch)
+                        .setContentText(fullMessageForWearVersion1)
+                        .build();
+
+        // Adds page with all text to support Wear 1.+.
+        NotificationCompat.WearableExtender wearableExtenderForWearVersion1 =
+                new NotificationCompat.WearableExtender()
+                        .setHintContentIntentLaunchesActivity(true)
+                        .addPage(chatHistoryForWearV1);
+
+        // 3. Set up main Intent for notification
+        Intent notifyIntent = new Intent(this, MessagingMainActivity.class);
+
+        PendingIntent mainPendingIntent =
+                PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+        // 4. Set up a RemoteInput Action, so users can input (keyboard, drawing, voice) directly
+        // from the notification without entering the app.
+        String replyLabel = getString(R.string.reply_label);
+        RemoteInput remoteInput =
+                new RemoteInput.Builder(MessagingIntentService.EXTRA_REPLY)
+                        .setLabel(replyLabel)
+                        .build();
+
+        Intent replyIntent = new Intent(this, MessagingIntentService.class);
+        replyIntent.setAction(MessagingIntentService.ACTION_REPLY);
+        PendingIntent replyActionPendingIntent = PendingIntent.getService(this, 0, replyIntent, 0);
+
+        // Enable action to appear inline on Wear 2.0 (24+). This means it will appear over the
+        // lower portion of the Notification for easy action (only possible for one action).
+        final NotificationCompat.Action.WearableExtender inlineActionForWear2_0 =
+                new NotificationCompat.Action.WearableExtender()
+                        .setHintDisplayActionInline(true)
+                        .setHintLaunchesActivity(false);
+
+        NotificationCompat.Action replyAction =
+                new NotificationCompat.Action.Builder(
+                                R.drawable.reply, replyLabel, replyActionPendingIntent)
+                        .addRemoteInput(remoteInput)
+                        // Allows system to generate replies by context of conversation
+                        .setAllowGeneratedReplies(true)
+                        // Add WearableExtender to enable inline actions
+                        .extend(inlineActionForWear2_0)
+                        .build();
+
+        // 5. Build and issue the notification
+        NotificationCompat.Builder notificationCompatBuilder =
+                new NotificationCompat.Builder(getApplicationContext());
+
+        GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);
+
+        // Builds and issues notification
+        notificationCompatBuilder
+                .setStyle(messagingStyle)
+                .setContentTitle(contentTitle)
+                .setContentText(messagingStyleCommsAppData.getContentText())
+                .setSmallIcon(R.drawable.watch)
+                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.avatar))
+                .setContentIntent(mainPendingIntent)
+                .setSubText(Integer.toString(messagingStyleCommsAppData.getNumberOfNewMessages()))
+                .addAction(replyAction)
+                .setCategory(Notification.CATEGORY_MESSAGE)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setVisibility(Notification.VISIBILITY_PRIVATE)
+                .extend(wearableExtenderForWearVersion1);
+
+        for (String name : messagingStyleCommsAppData.getParticipants()) {
+            notificationCompatBuilder.addPerson(name);
+        }
+
+        return notificationCompatBuilder;
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MessagingMainActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MessagingMainActivity.java
new file mode 100644
index 0000000..b3d6464
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MessagingMainActivity.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+
+/**
+ * Template class meant to include functionality for your Messaging App. (This project's main focus
+ * is on Notification Styles.)
+ */
+public class MessagingMainActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_messaging_main);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Cancel Notification
+        NotificationManager notificationManager =
+                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+
+        notificationManager.cancel(NotificationsActivity.NOTIFICATION_ID);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MockDatabase.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MockDatabase.java
new file mode 100644
index 0000000..421a719
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/MockDatabase.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.NotificationManager;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationCompat.MessagingStyle;
+
+import java.util.ArrayList;
+
+/** Mock data for each of the Notification Style Demos. */
+public final class MockDatabase {
+
+    public static MessagingStyleCommsAppData getMessagingStyleData() {
+        return MessagingStyleCommsAppData.getInstance();
+    }
+
+    /** Represents data needed for MessagingStyle Notification. */
+    public static class MessagingStyleCommsAppData {
+
+        private static MessagingStyleCommsAppData sInstance = null;
+
+        // Standard notification values
+        protected String mContentTitle;
+        protected String mContentText;
+        protected int mPriority;
+
+        // Style notification values
+        protected ArrayList<MessagingStyle.Message> mMessages;
+        // Basically, String of all mMessages
+        protected String mFullConversation;
+        // Name preferred when replying to chat
+        protected String mReplayName;
+        protected int mNumberOfNewMessages;
+        protected ArrayList<String> mParticipants;
+
+        // Notification channel values (O and above):
+        protected String mChannelId;
+        protected CharSequence mChannelName;
+        protected String mChannelDescription;
+        protected int mChannelImportance;
+        protected boolean mChannelEnableVibrate;
+        protected int mChannelLockscreenVisibility;
+
+        public static MessagingStyleCommsAppData getInstance() {
+            if (sInstance == null) {
+                sInstance = getSync();
+            }
+            return sInstance;
+        }
+
+        private static synchronized MessagingStyleCommsAppData getSync() {
+            if (sInstance == null) {
+                sInstance = new MessagingStyleCommsAppData();
+            }
+
+            return sInstance;
+        }
+
+        private MessagingStyleCommsAppData() {
+            // Standard notification values
+            // Content for API <24 (M and below) devices
+            mContentTitle = "2 Messages w/ Famous McFamously";
+            mContentText = "Dude! ... You know I am a Pesce-pescetarian. :P";
+            mPriority = NotificationCompat.PRIORITY_HIGH;
+
+            // Style notification values
+
+            // For each message, you need the timestamp, in this case, we are using arbitrary ones.
+            long currentTime = System.currentTimeMillis();
+
+            mMessages = new ArrayList<>();
+            mMessages.add(
+                    new MessagingStyle.Message(
+                            "What are you doing tonight?", currentTime - 4000, "Famous"));
+            mMessages.add(
+                    new MessagingStyle.Message(
+                            "I don't know, dinner maybe?", currentTime - 3000, null));
+            mMessages.add(new MessagingStyle.Message("Sounds good.", currentTime - 2000, "Famous"));
+            mMessages.add(new MessagingStyle.Message("How about BBQ?", currentTime - 1000, null));
+            // Last two are the newest message (2) from friend
+            mMessages.add(new MessagingStyle.Message("Hey!", currentTime, "Famous"));
+            mMessages.add(
+                    new MessagingStyle.Message(
+                            "You know I am a Pesce-pescetarian. :P", currentTime, "Famous"));
+
+            // String version of the mMessages above
+            mFullConversation =
+                    "Famous: What are you doing tonight?\n\n"
+                            + "Me: I don't know, dinner maybe?\n\n"
+                            + "Famous: Sounds good.\n\n"
+                            + "Me: How about BBQ?\n\n"
+                            + "Famous: Hey!\n\n"
+                            + "Famous: You know I am a Pesce-pescetarian. :P\n\n";
+
+            mNumberOfNewMessages = 2;
+
+            // Name preferred when replying to chat
+            mReplayName = "Me";
+
+            // If the phone is in "Do not disturb mode, the user will still be notified if
+            // the user(s) is starred as a favorite.
+            mParticipants = new ArrayList<>();
+            mParticipants.add("Famous McFamously");
+
+            // Notification channel values (for devices targeting 26 and above):
+            mChannelId = "channel_messaging_1";
+            // The user-visible name of the channel.
+            mChannelName = "Sample Messaging";
+            // The user-visible description of the channel.
+            mChannelDescription = "Sample Messaging Notifications";
+            mChannelImportance = NotificationManager.IMPORTANCE_MAX;
+            mChannelEnableVibrate = true;
+            mChannelLockscreenVisibility = NotificationCompat.VISIBILITY_PRIVATE;
+        }
+
+        public String getContentTitle() {
+            return mContentTitle;
+        }
+
+        public String getContentText() {
+            return mContentText;
+        }
+
+        public ArrayList<MessagingStyle.Message> getMessages() {
+            return mMessages;
+        }
+
+        public String getFullConversation() {
+            return mFullConversation;
+        }
+
+        public String getReplayName() {
+            return mReplayName;
+        }
+
+        public int getNumberOfNewMessages() {
+            return mNumberOfNewMessages;
+        }
+
+        public ArrayList<String> getParticipants() {
+            return mParticipants;
+        }
+
+        public int getPriority() {
+            return mPriority;
+        }
+
+        // Channel values (O and above) get methods:
+        public String getChannelId() {
+            return mChannelId;
+        }
+
+        public CharSequence getChannelName() {
+            return mChannelName;
+        }
+
+        public String getChannelDescription() {
+            return mChannelDescription;
+        }
+
+        public int getChannelImportance() {
+            return mChannelImportance;
+        }
+
+        public boolean isChannelEnableVibrate() {
+            return mChannelEnableVibrate;
+        }
+
+        public int getChannelLockscreenVisibility() {
+            return mChannelLockscreenVisibility;
+        }
+
+        @Override
+        public String toString() {
+            return getFullConversation();
+        }
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/NotificationsActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/NotificationsActivity.java
new file mode 100644
index 0000000..412b012
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/NotificationsActivity.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceFragment;
+import android.preference.SwitchPreference;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationCompat.MessagingStyle;
+import android.support.v4.app.NotificationManagerCompat;
+import android.support.v4.app.RemoteInput;
+import android.support.v4.content.ContextCompat;
+import android.support.wear.ambient.AmbientMode;
+import android.util.Log;
+
+public class NotificationsActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    public static final int NOTIFICATION_ID = 888;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Display the fragment as the main content.
+        getFragmentManager()
+                .beginTransaction()
+                .replace(android.R.id.content, new NotificationsPrefsFragment())
+                .commit();
+    }
+
+    public static class NotificationsPrefsFragment extends PreferenceFragment {
+
+        private static final String TAG = "NotificationsActivity";
+        private NotificationManagerCompat mNotificationManagerCompat;
+        private boolean mActionOn; // if true, displays in-line action
+        private boolean mAvatarOn; // if true, displays avatar of messenger
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            // Load the preferences from an XML resource
+            addPreferencesFromResource(R.xml.prefs_notifications);
+
+            mNotificationManagerCompat = NotificationManagerCompat.from(getActivity());
+
+            final SwitchPreference mActionSwitchPref =
+                    (SwitchPreference) findPreference(getString(R.string.key_pref_action));
+            final SwitchPreference mAvatarSwitchPref =
+                    (SwitchPreference) findPreference(getString(R.string.key_pref_avatar));
+            Preference mPushNotificationPref =
+                    findPreference(getString(R.string.key_pref_push_notification));
+
+            initInLineAction(mActionSwitchPref);
+            initAvatar(mAvatarSwitchPref);
+            initPushNotification(mPushNotificationPref);
+        }
+
+        public void initInLineAction(SwitchPreference switchPref) {
+            switchPref.setChecked(true);
+            mActionOn = switchPref.isChecked();
+            switchPref.setOnPreferenceChangeListener(
+                    new OnPreferenceChangeListener() {
+                        @Override
+                        public boolean onPreferenceChange(Preference preference, Object newValue) {
+                            mActionOn = (Boolean) newValue;
+                            return true;
+                        }
+                    });
+        }
+
+        public void initAvatar(SwitchPreference switchPref) {
+            switchPref.setChecked(true);
+            mAvatarOn = switchPref.isChecked();
+            switchPref.setOnPreferenceChangeListener(
+                    new OnPreferenceChangeListener() {
+                        @Override
+                        public boolean onPreferenceChange(Preference preference, Object newValue) {
+                            mAvatarOn = (Boolean) newValue;
+                            return true;
+                        }
+                    });
+        }
+
+        public void initPushNotification(Preference pref) {
+            pref.setOnPreferenceClickListener(
+                    new OnPreferenceClickListener() {
+                        @Override
+                        public boolean onPreferenceClick(Preference preference) {
+                            generateMessagingStyleNotification(getContext());
+                            return true;
+                        }
+                    });
+        }
+
+        /*
+         * Generates a MESSAGING_STYLE Notification that supports both Wear 1.+ and Wear 2.0. For
+         * devices on API level 24 (Wear 2.0) and after, displays MESSAGING_STYLE. Otherwise,
+         * displays a basic BIG_TEXT_STYLE.
+         *
+         * IMPORTANT NOTE:
+         * Notification Styles behave slightly different on Wear 2.0 when they are launched by a
+         * native/local Wear app, i.e., they will NOT expand when the user taps them but will
+         * instead take the user directly into the local app for the richest experience. In
+         * contrast, a bridged Notification launched from the phone will expand with the style
+         * details (whether there is a local app or not).
+         *
+         * If you want to enable an action on your Notification without launching the app, you can
+         * do so with the setHintDisplayActionInline() feature (shown below), but this only allows
+         * one action.
+         *
+         * If you wish to replicate the original experience of a bridged notification, please
+         * review the generateBigTextStyleNotification() method above to see how.
+         */
+        private void generateMessagingStyleNotification(Context context) {
+            Log.d(TAG, "generateMessagingStyleNotification()");
+
+            // Main steps for building a MESSAGING_STYLE notification:
+            //      0. Get your data
+            //      1. Retrieve Notification Channel for O and beyond devices (26+)
+            //      2. Build the MESSAGING_STYLE
+            //      3. Set up main Intent for notification
+            //      4. Set up RemoteInput (users can input directly from notification)
+            //      5. Build and issue the notification
+
+            // 0. Get your data (everything unique per Notification).
+            MockDatabase.MessagingStyleCommsAppData messagingStyleCommsAppData =
+                    MockDatabase.getMessagingStyleData();
+
+            // 1. Create/Retrieve Notification Channel for O and beyond devices (26+).
+            String notificationChannelId =
+                    createNotificationChannel(context, messagingStyleCommsAppData);
+
+            // 2. Build the Notification.Style (MESSAGING_STYLE)
+            String contentTitle = messagingStyleCommsAppData.getContentTitle();
+
+            MessagingStyle messagingStyle =
+                    new NotificationCompat.MessagingStyle(
+                                    messagingStyleCommsAppData.getReplayName())
+                            // You could set a different title to appear when the messaging style
+                            // is supported on device (24+) if you wish. In our case, we use the
+                            // same
+                            // title.
+                            .setConversationTitle(contentTitle);
+
+            // Adds all Messages
+            // Note: Messages include the text, timestamp, and sender
+            for (MessagingStyle.Message message : messagingStyleCommsAppData.getMessages()) {
+                messagingStyle.addMessage(message);
+            }
+
+            // 3. Set up main Intent for notification
+            Intent notifyIntent = new Intent(getActivity(), MessagingMainActivity.class);
+
+            PendingIntent mainPendingIntent =
+                    PendingIntent.getActivity(
+                            getActivity(), 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+            // 4. Set up a RemoteInput Action, so users can input (keyboard, drawing, voice)
+            // directly from the notification without entering the app.
+
+            // Create the RemoteInput specifying this key.
+            String replyLabel = getString(R.string.reply_label);
+            RemoteInput remoteInput =
+                    new RemoteInput.Builder(MessagingIntentService.EXTRA_REPLY)
+                            .setLabel(replyLabel)
+                            .build();
+
+            // Create PendingIntent for service that handles input.
+            Intent replyIntent = new Intent(getActivity(), MessagingIntentService.class);
+            replyIntent.setAction(MessagingIntentService.ACTION_REPLY);
+            PendingIntent replyActionPendingIntent =
+                    PendingIntent.getService(getActivity(), 0, replyIntent, 0);
+
+            // Enable action to appear inline on Wear 2.0 (24+). This means it will appear over the
+            // lower portion of the Notification for easy action (only possible for one action).
+            final NotificationCompat.Action.WearableExtender inlineActionForWear2 =
+                    new NotificationCompat.Action.WearableExtender()
+                            .setHintDisplayActionInline(mActionOn)
+                            .setHintLaunchesActivity(false);
+
+            NotificationCompat.Action replyAction =
+                    new NotificationCompat.Action.Builder(
+                                    R.drawable.reply, replyLabel, replyActionPendingIntent)
+                            .addRemoteInput(remoteInput)
+                            // Allows system to generate replies by context of conversation
+                            .setAllowGeneratedReplies(true)
+                            // Add WearableExtender to enable inline actions
+                            .extend(inlineActionForWear2)
+                            .build();
+
+            // 5. Build and issue the notification
+
+            // Because we want this to be a new notification (not updating current notification),
+            // we create a new Builder. Later, we update this same notification, so we need to save
+            // this Builder globally (as outlined earlier).
+
+            // Notification Channel Id is ignored for Android pre O (26).
+            NotificationCompat.Builder notificationCompatBuilder =
+                    new NotificationCompat.Builder(context, notificationChannelId);
+
+            GlobalNotificationBuilder.setNotificationCompatBuilderInstance(
+                    notificationCompatBuilder);
+
+            // Builds and issues notification
+            notificationCompatBuilder
+                    // MESSAGING_STYLE sets title and content for Wear 1.+ and Wear 2.0 devices.
+                    .setStyle(messagingStyle)
+                    .setContentTitle(contentTitle)
+                    .setContentText(messagingStyleCommsAppData.getContentText())
+                    .setSmallIcon(R.drawable.watch)
+                    .setContentIntent(mainPendingIntent)
+                    .setColor(ContextCompat.getColor(context, R.color.background))
+                    .setDefaults(NotificationCompat.DEFAULT_ALL)
+
+                    // Number of new notifications for API <24 (Wear 1.+) devices
+                    .setSubText(
+                            Integer.toString(messagingStyleCommsAppData.getNumberOfNewMessages()))
+                    .addAction(replyAction)
+                    .setCategory(Notification.CATEGORY_MESSAGE)
+
+                    // Sets priority for 25 and below. For 26 and above, 'priority' is deprecated
+                    // for 'importance' which is set in the NotificationChannel. The integers
+                    // representing 'priority' are different from 'importance', so make sure you
+                    // don't mix them.
+                    .setPriority(messagingStyleCommsAppData.getPriority())
+
+                    // Sets lock-screen visibility for 25 and below. For 26 and above, lock screen
+                    // visibility is set in the NotificationChannel.
+                    .setVisibility(messagingStyleCommsAppData.getChannelLockscreenVisibility());
+
+            notificationCompatBuilder.setLargeIcon(
+                    BitmapFactory.decodeResource(
+                            getResources(), mAvatarOn ? R.drawable.avatar : R.drawable.watch));
+
+            // If the phone is in "Do not disturb mode, the user will still be notified if
+            // the sender(s) is starred as a favorite.
+            for (String name : messagingStyleCommsAppData.getParticipants()) {
+                notificationCompatBuilder.addPerson(name);
+            }
+
+            Notification notification = notificationCompatBuilder.build();
+            mNotificationManagerCompat.notify(NOTIFICATION_ID, notification);
+
+            // Close app to demonstrate notification in steam.
+            getActivity().finish();
+        }
+
+        private String createNotificationChannel(
+                Context context, MockDatabase.MessagingStyleCommsAppData mockNotificationData) {
+
+            // NotificationChannels are required for Notifications on O (API 26) and above.
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+
+                // The id of the channel.
+                String channelId = mockNotificationData.getChannelId();
+
+                // The user-visible name of the channel.
+                CharSequence channelName = mockNotificationData.getChannelName();
+                // The user-visible description of the channel.
+                String channelDescription = mockNotificationData.getChannelDescription();
+                int channelImportance = mockNotificationData.getChannelImportance();
+                boolean channelEnableVibrate = mockNotificationData.isChannelEnableVibrate();
+                int channelLockscreenVisibility =
+                        mockNotificationData.getChannelLockscreenVisibility();
+
+                // Initializes NotificationChannel.
+                NotificationChannel notificationChannel =
+                        new NotificationChannel(channelId, channelName, channelImportance);
+                notificationChannel.setDescription(channelDescription);
+                notificationChannel.enableVibration(channelEnableVibrate);
+                notificationChannel.setLockscreenVisibility(channelLockscreenVisibility);
+
+                // Adds NotificationChannel to system. Attempting to create an existing notification
+                // channel with its original values performs no operation, so it's safe to perform
+                // the below sequence.
+                NotificationManager notificationManager =
+                        (NotificationManager)
+                                context.getSystemService(Context.NOTIFICATION_SERVICE);
+                notificationManager.createNotificationChannel(notificationChannel);
+
+                return channelId;
+            } else {
+                // Returns null for pre-O (26) devices.
+                return null;
+            }
+        }
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/OpenOnPhoneAnimationActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/OpenOnPhoneAnimationActivity.java
new file mode 100644
index 0000000..db1ae6e
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/OpenOnPhoneAnimationActivity.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.graphics.drawable.Animatable2.AnimationCallback;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.widget.ImageView;
+
+public class OpenOnPhoneAnimationActivity extends Activity
+        implements AmbientMode.AmbientCallbackProvider {
+    private AnimationCallback mAnimationCallback;
+    private AnimatedVectorDrawable mAnimatedVectorDrawablePhone;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_open_on_phone_animation);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        mAnimationCallback =
+                new AnimationCallback() {
+                    @Override
+                    public void onAnimationEnd(Drawable drawable) {
+                        super.onAnimationEnd(drawable);
+                        // Go back to main Dialogs screen after animation.
+                        finish();
+                    }
+                };
+
+        // Play 'swipe left' animation only once.
+        ImageView phoneImage = findViewById(R.id.open_on_phone_animation_image);
+        mAnimatedVectorDrawablePhone = (AnimatedVectorDrawable) phoneImage.getDrawable();
+        mAnimatedVectorDrawablePhone.registerAnimationCallback(mAnimationCallback);
+        mAnimatedVectorDrawablePhone.start();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mAnimatedVectorDrawablePhone.unregisterAnimationCallback(mAnimationCallback);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/PhotoCarouselActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/PhotoCarouselActivity.java
new file mode 100644
index 0000000..3c53b03
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/PhotoCarouselActivity.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageView;
+
+public class PhotoCarouselActivity extends Activity
+        implements AmbientMode.AmbientCallbackProvider, OnClickListener {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_photo_carousel);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Grab reference to each image in activity_photo_carousel.
+        ImageView catImage = findViewById(R.id.cat_image);
+        catImage.setTag(R.drawable.cats);
+        catImage.setOnClickListener(this);
+
+        ImageView dogImage = findViewById(R.id.dog_image);
+        dogImage.setTag(R.drawable.dog);
+        dogImage.setOnClickListener(this);
+
+        ImageView hamsterImage = findViewById(R.id.hamster_image);
+        hamsterImage.setTag(R.drawable.hamster);
+        hamsterImage.setOnClickListener(this);
+
+        ImageView birdImage = findViewById(R.id.bird_image);
+        birdImage.setTag(R.drawable.birds);
+        birdImage.setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View v) {
+        Intent intent = new Intent(getApplicationContext(), ZoomImageActivity.class);
+        intent.putExtra(getString(R.string.intent_extra_image), (int) v.getTag());
+        startActivity(intent);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ProgressActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ProgressActivity.java
new file mode 100644
index 0000000..07ed344
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ProgressActivity.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ProgressActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+    private List<ListsItem> mItems;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_lists);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Create a list of items for adapter to display.
+        mItems = new ArrayList<>();
+        mItems.add(new ListsItem(R.string.full_screen, FullScreenActivity.class));
+        mItems.add(new ListsItem(R.string.in_line, InLineActivity.class));
+
+        // Initialize an adapter and set it to ListView listView.
+        ListViewAdapter adapter = new ListViewAdapter(this, mItems);
+        final ListView listView = findViewById(R.id.list_view_lists);
+        listView.setAdapter(adapter);
+
+        // Set header of listView to be the title from title_layout.
+        LayoutInflater inflater = LayoutInflater.from(this);
+        View titleLayout = inflater.inflate(R.layout.title_layout, null);
+        TextView titleView = titleLayout.findViewById(R.id.title_text);
+        titleView.setText(R.string.progress);
+        titleView.setOnClickListener(null); // make title non-clickable.
+
+        listView.addHeaderView(titleView);
+
+        // Goes to a new screen when you click on one of the list items.
+        // Dependent upon position of click.
+        listView.setOnItemClickListener(
+                new AdapterView.OnItemClickListener() {
+                    @Override
+                    public void onItemClick(
+                            AdapterView<?> parent, View view, int position, long id) {
+                        mItems.get(position - listView.getHeaderViewsCount())
+                                .launchActivity(getApplicationContext());
+                    }
+                });
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ProgressBarPreference.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ProgressBarPreference.java
new file mode 100644
index 0000000..b19195e
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ProgressBarPreference.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.content.Context;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class ProgressBarPreference extends Preference {
+
+    public ProgressBarPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public ProgressBarPreference(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected View onCreateView(ViewGroup parent) {
+        super.onCreateView(parent);
+        LayoutInflater inflater =
+                (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        return inflater.inflate(R.layout.progress_bar_with_text_layout, parent, false);
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/RadioListActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/RadioListActivity.java
new file mode 100644
index 0000000..e8d26b2
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/RadioListActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.widget.TextView;
+
+public class RadioListActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_radio_list);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        TextView titleView = findViewById(R.id.radio_list_title);
+        titleView.setText(R.string.radio_list);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/SampleAppConstants.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/SampleAppConstants.java
new file mode 100644
index 0000000..b259980
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/SampleAppConstants.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+public class SampleAppConstants {
+    /** {@value #NORMAL} Used when sending information to an Adapter class */
+    public static final int NORMAL = 1;
+
+    /** {@value #HEADER_FOOTER} Used when sending information to an Adapter class */
+    public static final int HEADER_FOOTER = 2;
+
+    /** {@value #PROGRESS_BAR} Used when sending information to an Adapter class */
+    public static final int PROGRESS_BAR = 3;
+
+    /** {@value #SWITCH} Used when sending information to an Adapter class */
+    public static final int SWITCH = 4;
+
+    /** {@value #TITLE} Used when sending information to an Adapter class */
+    public static final int TITLE = 5;
+
+    /**
+     * {@value #END_OF_LONG_LIST} Used to check if at the end of long list Used in
+     * LongListRecyclerviewAdapter
+     */
+    public static final int END_OF_LONG_LIST = 45;
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ScalingScrollLayoutCallback.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ScalingScrollLayoutCallback.java
new file mode 100644
index 0000000..00b4226
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ScalingScrollLayoutCallback.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.wear.widget.WearableLinearLayoutManager;
+import android.view.View;
+
+public class ScalingScrollLayoutCallback extends WearableLinearLayoutManager.LayoutCallback {
+
+    /** How much should we scale the icon at most. */
+    private static final float MAX_ICON_PROGRESS = 0.65f;
+
+    @Override
+    public void onLayoutFinished(View child, RecyclerView parent) {
+
+        // Figure out % progress from top to bottom.
+        float centerOffset = (child.getHeight() / 2.0f) / parent.getHeight();
+        float yRelativeToCenterOffset = (child.getY() / parent.getHeight()) + centerOffset;
+
+        // Normalize for center.
+        float progressToCenter = Math.abs(0.5f - yRelativeToCenterOffset);
+
+        // Adjust to the maximum scale.
+        progressToCenter = Math.min(progressToCenter, MAX_ICON_PROGRESS);
+
+        child.setScaleX(1 - progressToCenter);
+        child.setScaleY(1 - progressToCenter);
+    }
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ZoomImageActivity.java b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ZoomImageActivity.java
new file mode 100644
index 0000000..27a24d1
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/java/com/example/android/wearable/wear/wearaccessibilityapp/ZoomImageActivity.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.wearable.wear.wearaccessibilityapp;
+
+import android.app.Activity;
+import android.content.res.Resources.NotFoundException;
+import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
+import android.widget.ImageView;
+
+public class ZoomImageActivity extends Activity implements AmbientMode.AmbientCallbackProvider {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_zoom_image);
+
+        AmbientMode.attachAmbientSupport(this);
+
+        // Check if integer was actually given.
+        if (!(getIntent().hasExtra(getString(R.string.intent_extra_image)))) {
+            throw new NotFoundException("Expecting extras");
+        }
+
+        // Grab the resource id from extras and set the image resource.
+        int value = getIntent().getIntExtra(getString(R.string.intent_extra_image), 0);
+        ImageView expandedImage = findViewById(R.id.expanded_image);
+        expandedImage.setImageResource(value);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {}
+}
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_0.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_0.xml
new file mode 100644
index 0000000..93776e9
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.33333333,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_1.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_1.xml
new file mode 100644
index 0000000..50d45ae
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_1.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.16666666667,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_10.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_10.xml
new file mode 100644
index 0000000..6c9621f
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_10.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.16666666667,0.16666666667 0.2,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_11.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_11.xml
new file mode 100644
index 0000000..0db24f5
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_11.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.00099999999999,0.0 0.66666667,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_12.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_12.xml
new file mode 100644
index 0000000..da23f6a
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_12.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.000999999999998,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_2.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_2.xml
new file mode 100644
index 0000000..a86dad0
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_2.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.001,0.0 0.9999,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_3.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_3.xml
new file mode 100644
index 0000000..f25a18b
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_3.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.0001,0.0 0.9999,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_4.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_4.xml
new file mode 100644
index 0000000..516d5e7
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_4.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.16666666667,0.16666666667 0.83333333333,0.83333333333 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_5.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_5.xml
new file mode 100644
index 0000000..48c68c9
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_5.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.4,0.0 0.83333333333,0.83333333333 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_6.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_6.xml
new file mode 100644
index 0000000..6c35d4c
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_6.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.16666666667,0.16666666667 0.66666667,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_7.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_7.xml
new file mode 100644
index 0000000..21aa274
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_7.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.2,0.1 0.2,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_8.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_8.xml
new file mode 100644
index 0000000..e1b7881
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_8.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.4,0.4 0.2,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_9.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_9.xml
new file mode 100644
index 0000000..4f8c154
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_animation_interpolator_9.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.8,0.0 0.83333333333,0.955555555555 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_ellipse_7_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_ellipse_7_animation.xml
new file mode 100644
index 0000000..f887a27
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_ellipse_7_animation.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="scaleX"
+            android:valueFrom="0.75"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_2" />
+        <objectAnimator
+            android:duration="1833"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="scaleY"
+            android:valueFrom="0.75"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_2" />
+        <objectAnimator
+            android:duration="1833"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_1" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_ellipse_8_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_ellipse_8_animation.xml
new file mode 100644
index 0000000..8375908
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_ellipse_8_animation.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="scaleX"
+            android:valueFrom="0.2"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_8" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_3" />
+        <objectAnimator
+            android:duration="1833"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_12" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="scaleY"
+            android:valueFrom="0.2"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_8" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_3" />
+        <objectAnimator
+            android:duration="1833"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_12" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_path_7_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_path_7_animation.xml
new file mode 100644
index 0000000..6e3a479
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_path_7_animation.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-20.5 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueTo="M 0.0,-20.5 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-20.5 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueTo="M 0.0,-54.5659637451 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218536377 -4.5699005127,76.4127655029 -20.6393432617,76.4451141357 c -16.069442749,0.0323486328125 -20.3606567383,-65.123260498 -20.3606567383,-76.4451141357 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_5" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-54.5659637451 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218536377 -4.5699005127,76.4127655029 -20.6393432617,76.4451141357 c -16.069442749,0.0323486328125 -20.3606567383,-65.123260498 -20.3606567383,-76.4451141357 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueTo="M 0.0,-54.5659179688 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_10" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-54.5659179688 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueTo="M 0.0,-54.5659179688 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.7"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.7"
+            android:valueTo="0.7"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_2" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.7"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_11" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_path_8_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_path_8_animation.xml
new file mode 100644
index 0000000..109c8c3
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_path_8_animation.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-20.5 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueTo="M 0.0,-20.5 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_8" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-20.5 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueTo="M 0.0,-83.0 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -20.365234375,98.5 -20.365234375,98.5 c 0.0,0.0 -20.634765625,-87.1781616211 -20.634765625,-98.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_5" />
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-83.0 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -20.365234375,98.5 -20.365234375,98.5 c 0.0,0.0 -20.634765625,-87.1781616211 -20.634765625,-98.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueTo="M 0.0,-80.4920959473 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_4" />
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-80.4920959473 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+            android:valueTo="M 0.0,-63.2420959473 c 1.10456848145,0.0 2.0,0.895431518555 2.0,2.0 c 0.0,1.10456848145 -0.895431518555,2.0 -2.0,2.0 c -1.10456848145,0.0 -2.0,-0.895431518555 -2.0,-2.0 c 0.0,-1.10456848145 0.895431518555,-2.0 2.0,-2.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_6" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-63.2420959473 c 1.10456848145,0.0 2.0,0.895431518555 2.0,2.0 c 0.0,1.10456848145 -0.895431518555,2.0 -2.0,2.0 c -1.10456848145,0.0 -2.0,-0.895431518555 -2.0,-2.0 c 0.0,-1.10456848145 0.895431518555,-2.0 2.0,-2.0 Z"
+            android:valueTo="M 0.0,-63.2420959473 c 1.10456848145,0.0 2.0,0.895431518555 2.0,2.0 c 0.0,1.10456848145 -0.895431518555,2.0 -2.0,2.0 c -1.10456848145,0.0 -2.0,-0.895431518555 -2.0,-2.0 c 0.0,-1.10456848145 0.895431518555,-2.0 2.0,-2.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_0" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_7" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_3" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="fillAlpha"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_11" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_swipeupbluecircle_2_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_swipeupbluecircle_2_animation.xml
new file mode 100644
index 0000000..afeb868
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_swipeupbluecircle_2_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="666"
+            android:propertyName="translateX"
+            android:valueFrom="153.575"
+            android:valueTo="100.65667"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_9" />
+        <objectAnimator
+            android:duration="1833"
+            android:propertyName="translateX"
+            android:valueFrom="100.65667"
+            android:valueTo="100.65667"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_1" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_swipeuptrace_2_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_swipeuptrace_2_animation.xml
new file mode 100644
index 0000000..afeb868
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_swipe_left_long_g_swipeuptrace_2_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="666"
+            android:propertyName="translateX"
+            android:valueFrom="153.575"
+            android:valueTo="100.65667"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_9" />
+        <objectAnimator
+            android:duration="1833"
+            android:propertyName="translateX"
+            android:valueFrom="100.65667"
+            android:valueTo="100.65667"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_swipe_left_long_g_animation_interpolator_1" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_0.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_0.xml
new file mode 100644
index 0000000..d5c70b8
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.4,0.4 0.509350957076,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_1.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_1.xml
new file mode 100644
index 0000000..50d45ae
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_1.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.16666666667,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_2.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_2.xml
new file mode 100644
index 0000000..10c53de
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_2.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.0001,0.0 1.0,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_3.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_3.xml
new file mode 100644
index 0000000..1fbe9cf
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_3.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.001,0.0 1.0,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_4.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_4.xml
new file mode 100644
index 0000000..4488f6a
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_4.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.2,0.3 0.2,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_5.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_5.xml
new file mode 100644
index 0000000..de2dc76
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_5.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.001,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_6.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_6.xml
new file mode 100644
index 0000000..8768e5d
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_animation_interpolator_6.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.001,0.0 0.66666667,1.0 1.0,1.0" />
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_ellipse_21_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_ellipse_21_animation.xml
new file mode 100644
index 0000000..bc764f0
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_ellipse_21_animation.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleX"
+            android:valueFrom="0.5"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="0.5"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_5" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="scaleX"
+            android:valueFrom="0.5"
+            android:valueTo="0.5"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleY"
+            android:valueFrom="0.5"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="0.5"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_5" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="scaleY"
+            android:valueFrom="0.5"
+            android:valueTo="0.5"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_1" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_ellipse_22_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_ellipse_22_animation.xml
new file mode 100644
index 0000000..304d6e1
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_ellipse_22_animation.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleX"
+            android:valueFrom="0.5"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_4" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="0.5"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_2" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="scaleX"
+            android:valueFrom="0.5"
+            android:valueTo="0.5"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleY"
+            android:valueFrom="0.5"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_4" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="0.5"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_2" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="scaleY"
+            android:valueFrom="0.5"
+            android:valueTo="0.5"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_path_23_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_path_23_animation.xml
new file mode 100644
index 0000000..7ced20c
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_path_23_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.7"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.7"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_3" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_path_24_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_path_24_animation.xml
new file mode 100644
index 0000000..dea5090
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_path_24_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_4" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_2" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_rectangle_path_3_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_rectangle_path_3_animation.xml
new file mode 100644
index 0000000..6582072
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/anim/oobe_tap_rectangle_path_3_animation.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="1000"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-25.0 l 0.0,0.0 c 13.807118745,0.0 25.0,11.192881255 25.0,25.0 l 0.0,0.0 c 0.0,13.807118745 -11.192881255,25.0 -25.0,25.0 l 0.0,0.0 c -13.807118745,0.0 -25.0,-11.192881255 -25.0,-25.0 l 0.0,0.0 c 0.0,-13.807118745 11.192881255,-25.0 25.0,-25.0 Z"
+            android:valueTo="M 0.0,-75.0 l 0.0,0.0 c 41.421356235,0.0 75.0,33.578643765 75.0,75.0 l 0.0,0.0 c 0.0,41.421356235 -33.578643765,75.0 -75.0,75.0 l 0.0,0.0 c -41.421356235,0.0 -75.0,-33.578643765 -75.0,-75.0 l 0.0,0.0 c 0.0,-41.421356235 33.578643765,-75.0 75.0,-75.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_0" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-75.0 l 0.0,0.0 c 41.421356235,0.0 75.0,33.578643765 75.0,75.0 l 0.0,0.0 c 0.0,41.421356235 -33.578643765,75.0 -75.0,75.0 l 0.0,0.0 c -41.421356235,0.0 -75.0,-33.578643765 -75.0,-75.0 l 0.0,0.0 c 0.0,-41.421356235 33.578643765,-75.0 75.0,-75.0 Z"
+            android:valueTo="M 0.0,-75.0 l 0.0,0.0 c 41.421356235,0.0 75.0,33.578643765 75.0,75.0 l 0.0,0.0 c 0.0,41.421356235 -33.578643765,75.0 -75.0,75.0 l 0.0,0.0 c -41.421356235,0.0 -75.0,-33.578643765 -75.0,-75.0 l 0.0,0.0 c 0.0,-41.421356235 33.578643765,-75.0 75.0,-75.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.2"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.2"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_6" />
+        <objectAnimator
+            android:duration="1500"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@anim/oobe_tap_animation_interpolator_1" />
+    </set>
+</set>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/accept_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/accept_circle.xml
new file mode 100644
index 0000000..40eb322
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/accept_circle.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorAccent"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="24.0"
+            android:viewportWidth="24.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/accessibility_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/accessibility_circle.xml
new file mode 100644
index 0000000..53f55f7
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/accessibility_circle.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorPrimaryDark"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="24.0"
+            android:viewportWidth="24.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M20.5,6c-2.61,0.7 -5.67,1 -8.5,1s-5.89,-0.3 -8.5,-1L3,8c1.86,
+                        0.5 4,0.83 6,1v13h2v-6h2v6h2V9c2,-0.17 4.14,-0.5 6,-1l-0.5,-2zM12,6c1.1,
+                        0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/arrow.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/arrow.xml
new file mode 100644
index 0000000..537afb0
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/arrow.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24dp">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
+</vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/arrow_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/arrow_circle.xml
new file mode 100644
index 0000000..ce027e0
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/arrow_circle.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorPrimaryDark"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="48.0"
+            android:viewportWidth="48.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M24,8l-2.83,2.83L32.34,22H8v4h24.34L21.17,37.17 24,40l16,-16z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/avatar.png b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/avatar.png
new file mode 100644
index 0000000..7953487
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/avatar.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/birds.png b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/birds.png
new file mode 100644
index 0000000..724f4e6
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/birds.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/bow.png b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/bow.png
new file mode 100644
index 0000000..6c6b336
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/bow.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/cats.png b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/cats.png
new file mode 100644
index 0000000..ebd2eac
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/cats.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/circle.xml
new file mode 100644
index 0000000..875c8b1
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/circle.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<shape xmlns:android="http//schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid
+        android:color="#ffffffff"/>
+    <size
+        android:height="40dp"
+        android:width="40dp"/>
+</shape>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/controls_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/controls_circle.xml
new file mode 100644
index 0000000..dda9501
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/controls_circle.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorPrimaryDark"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="24.0"
+            android:viewportWidth="24.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,
+                        -10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/deny_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/deny_circle.xml
new file mode 100644
index 0000000..3633248
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/deny_circle.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorButtonNormal"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="24.0"
+            android:viewportWidth="24.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,
+                17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/dialogs_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/dialogs_circle.xml
new file mode 100644
index 0000000..8129fbe
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/dialogs_circle.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorPrimaryDark"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="24.0"
+            android:viewportWidth="24.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,
+                        -10S17.52,2 12,2zM13,17h-2v-2h2v2zM13,13h-2L11,7h2v6z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/dog.png b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/dog.png
new file mode 100644
index 0000000..30ff7f7
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/dog.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/hamster.png b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/hamster.png
new file mode 100644
index 0000000..c6f67df
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/hamster.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/heart.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/heart.xml
new file mode 100644
index 0000000..1b46dc3
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/heart.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24dp">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,
+                3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,
+                5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
+</vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/heart_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/heart_circle.xml
new file mode 100644
index 0000000..4d485f6
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/heart_circle.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorPrimaryDark"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/heart"
+        android:gravity="center">
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/ic_view_list_white_1x_web_48dp.png b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/ic_view_list_white_1x_web_48dp.png
new file mode 100644
index 0000000..b81d910
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/ic_view_list_white_1x_web_48dp.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/launcher_image.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/launcher_image.xml
new file mode 100644
index 0000000..f56e0be
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/launcher_image.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/icon_color"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="24.0"
+            android:viewportWidth="24.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M20,12c0,-2.54 -1.19,-4.81 -3.04,-6.27L16,0H8l-0.95,5.73C5.19,
+                        7.19 4,9.45 4,12s1.19,4.81 3.05,6.27L8,24h8l0.96,-5.73C18.81,16.81 20,
+                        14.54 20,12zM6,12c0,-3.31 2.69,-6 6,-6s6,2.69 6,6 -2.69,6 -6,6 -6,
+                        -2.69 -6,-6z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/list_arrow.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/list_arrow.xml
new file mode 100644
index 0000000..537afb0
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/list_arrow.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24dp">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
+</vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/lists_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/lists_circle.xml
new file mode 100644
index 0000000..7d579d1
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/lists_circle.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorPrimaryDark"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="24.0"
+            android:viewportWidth="24.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M-278.33,-374.17h76v76h-76z"/>
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M2,4h4v4h-4z"/>
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M8,4h14v4h-14z"/>
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M2,10h4v4h-4z"/>
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M8,10h14v4h-14z"/>
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M2,16h4v4h-4z"/>
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M8,16h14v4h-14z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/notifications_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/notifications_circle.xml
new file mode 100644
index 0000000..d547979
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/notifications_circle.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorPrimaryDark"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="24.0"
+            android:viewportWidth="24.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,
+                        -1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,
+                        2v1h16v-1l-2,-2zM13,16h-2v-2h2v2zM13,12h-2L11,8h2v4zM12,22c1.1,0 2,
+                        -0.9 2,-2h-4c0,1.1 0.89,2 2,2z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_swipe_left_long.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_swipe_left_long.xml
new file mode 100644
index 0000000..2aa7613
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_swipe_left_long.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="oobe_swipe_left_long_g"
+    android:width="95dp"
+    android:viewportWidth="190"
+    android:height="39dp"
+    android:viewportHeight="78" >
+    <group
+        android:name="swipeuptrace_2"
+        android:translateX="153.575"
+        android:translateY="39"
+        android:scaleX="1.82"
+        android:scaleY="1.82"
+        android:rotation="270" >
+        <group
+            android:name="swipeuptrace_pivot_2"
+            android:translateX="-1.95508"
+            android:translateY="111.925" >
+            <group
+                android:name="ellipse_7"
+                android:translateX="1.95508"
+                android:translateY="-111.77148"
+                android:scaleX="0.75"
+                android:scaleY="0.75" >
+                <path
+                    android:name="path_7"
+                    android:pathData="M 0.0,-20.5 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+                    android:fillColor="#FF000000"
+                    android:fillAlpha="0" />
+            </group>
+        </group>
+    </group>
+    <group
+        android:name="swipeupbluecircle_2"
+        android:translateX="153.575"
+        android:translateY="39"
+        android:rotation="270" >
+        <group
+            android:name="swipeupbluecircle_pivot_2"
+            android:translateX="-1.95508"
+            android:translateY="111.925" >
+            <group
+                android:name="ellipse_8"
+                android:translateX="1.95508"
+                android:translateY="-111.77148"
+                android:scaleX="0.2"
+                android:scaleY="0.2" >
+                <path
+                    android:name="path_8"
+                    android:pathData="M 0.0,-20.5 c 11.3218383789,0.0 20.5,9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,-20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"
+                    android:fillColor="#FF5E97F6"
+                    android:fillAlpha="0" />
+            </group>
+        </group>
+    </group>
+</vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_swipe_left_long_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_swipe_left_long_animation.xml
new file mode 100644
index 0000000..abae0f4
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_swipe_left_long_animation.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/oobe_swipe_left_long" >
+    <target
+        android:name="swipeuptrace_2"
+        android:animation="@anim/oobe_swipe_left_long_g_swipeuptrace_2_animation" />
+    <target
+        android:name="ellipse_7"
+        android:animation="@anim/oobe_swipe_left_long_g_ellipse_7_animation" />
+    <target
+        android:name="path_7"
+        android:animation="@anim/oobe_swipe_left_long_g_path_7_animation" />
+    <target
+        android:name="swipeupbluecircle_2"
+        android:animation="@anim/oobe_swipe_left_long_g_swipeupbluecircle_2_animation" />
+    <target
+        android:name="ellipse_8"
+        android:animation="@anim/oobe_swipe_left_long_g_ellipse_8_animation" />
+    <target
+        android:name="path_8"
+        android:animation="@anim/oobe_swipe_left_long_g_path_8_animation" />
+</animated-vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_tap.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_tap.xml
new file mode 100644
index 0000000..2a4e2e6
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_tap.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="80dp"
+    android:name="oobe_tap"
+    android:viewportHeight="160"
+    android:viewportWidth="160"
+    android:width="80dp">
+    <group
+        android:name="tapripple"
+        android:translateX="80.25"
+        android:translateY="79.48125">
+        <group
+            android:name="tapripple_pivot"
+            android:translateX="-1.78031"
+            android:translateY="55.82941">
+            <group
+                android:name="rectangle_5"
+                android:scaleY="1.03255"
+                android:translateX="1.8623"
+                android:translateY="-49.13672">
+                <group
+                    android:name="rectangle_path_3_position"
+                    android:translateY="-6">
+                    <path
+                        android:fillAlpha="0"
+                        android:fillColor="#FF000000"
+                        android:name="rectangle_path_3"
+                        android:pathData="M 0.0,-25.0 l 0.0,0.0 c 13.807118745,0.0 25.0,
+                                11.192881255 25.0,25.0 l 0.0,0.0 c 0.0,13.807118745 -11.192881255,
+                                25.0 -25.0,25.0 l 0.0,0.0 c -13.807118745,0.0 -25.0,
+                                -11.192881255 -25.0,-25.0 l 0.0,0.0 c 0.0,
+                                -13.807118745 11.192881255,-25.0 25.0,-25.0 Z"/>
+                </group>
+            </group>
+        </group>
+    </group>
+    <group
+        android:name="taptrace"
+        android:scaleX="1.82"
+        android:scaleY="1.82"
+        android:translateX="80.25"
+        android:translateY="79.48125">
+        <group
+            android:name="taptrace_pivot"
+            android:translateX="-1.95508"
+            android:translateY="111.925">
+            <group
+                android:name="ellipse_21"
+                android:scaleX="0.5"
+                android:scaleY="0.5"
+                android:translateX="1.95508"
+                android:translateY="-111.77148">
+                <path
+                    android:fillAlpha="0"
+                    android:fillColor="#FF000000"
+                    android:name="path_23"
+                    android:pathData="M 0.0,-20.5 c 11.3218383789,0.0 20.5,
+                            9.17816162109 20.5,20.5 c 0.0,11.3218383789 -9.17816162109,
+                            20.5 -20.5,20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,
+                            -20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"/>
+            </group>
+        </group>
+    </group>
+    <group
+        android:name="tapblue"
+        android:translateX="80.25"
+        android:translateY="79.48125">
+        <group
+            android:name="tapblue_pivot"
+            android:translateX="-1.95508"
+            android:translateY="111.925">
+            <group
+                android:name="ellipse_22"
+                android:scaleX="0.5"
+                android:scaleY="0.5"
+                android:translateX="1.95508"
+                android:translateY="-111.77148">
+                <path
+                    android:fillAlpha="0"
+                    android:fillColor="#FF5E97F6"
+                    android:name="path_24"
+                    android:pathData="M 0.0,-20.5 c 11.3218383789,0.0 20.5,9.17816162109 20.5,
+                            20.5 c 0.0,11.3218383789 -9.17816162109,20.5 -20.5,
+                            20.5 c -11.3218383789,0.0 -20.5,-9.17816162109 -20.5,
+                            -20.5 c 0.0,-11.3218383789 9.17816162109,-20.5 20.5,-20.5 Z"/>
+            </group>
+        </group>
+    </group>
+</vector>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_tap_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_tap_animation.xml
new file mode 100644
index 0000000..1ad9b09
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/oobe_tap_animation.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/oobe_tap">
+    <target
+        android:animation="@anim/oobe_tap_rectangle_path_3_animation"
+        android:name="rectangle_path_3"/>
+    <target
+        android:animation="@anim/oobe_tap_ellipse_21_animation"
+        android:name="ellipse_21"/>
+    <target
+        android:animation="@anim/oobe_tap_path_23_animation"
+        android:name="path_23"/>
+    <target
+        android:animation="@anim/oobe_tap_ellipse_22_animation"
+        android:name="ellipse_22"/>
+    <target
+        android:animation="@anim/oobe_tap_path_24_animation"
+        android:name="path_24"/>
+</animated-vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/open_in_phone_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/open_in_phone_circle.xml
new file mode 100644
index 0000000..80af24d
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/open_in_phone_circle.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorButtonNormal"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector android:width="24dp"
+            android:height="24dp"
+            android:viewportWidth="24.0"
+            android:viewportHeight="24.0">
+            <path
+                android:pathData="M16.5,2.7H7.4c-0.3,0 -0.5,0.2 -0.5,0.5v7.4h0.8V5.1C7.7,5 7.8,
+                        5 7.8,5h8.2c0.1,0 0.1,0.1 0.1,0.1v13.5c0,0.1 -0.1,0.1 -0.1,0.1H7.8c-0.1,
+                        0 -0.1,-0.1 -0.1,-0.1v-5.2H6.9v7.4c0,0.3 0.2,0.5 0.5,0.5h9.1c0.3,0 0.5,
+                        -0.2 0.5,-0.5V3.2C17,2.9 16.8,2.7 16.5,2.7z"
+                 android:fillColor="#FFFFFF"/>
+            <path android:pathData="M9.5,13.9l0.8,0.8l2.7,-2.7l-2.7,-2.7l-0.8,0.8l1.4,
+                    1.4H5.3v1.1h5.6L9.5,13.9z"
+                    android:fillColor="#FFFFFF"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/open_on_phone.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/open_on_phone.xml
new file mode 100644
index 0000000..718160b
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/open_on_phone.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:name="open_on_phone"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24dp">
+    <group
+        android:name="phone"
+        android:scaleX="0.1507"
+        android:scaleY="0.1507"
+        android:translateX="32"
+        android:translateY="32">
+        <group
+            android:name="shape_1">
+            <path
+                android:fillColor="#FFFFFFFF"
+                android:name="path_1"
+                android:pathData="M 99.625,-194.5 c 0.0,0.0 -182.125,0.0 -194.25,0.0 c -12.125,
+                        0.0 -11.875,11.0 -11.875,11.0 c 0.0,0.0 0.00002,151.259307861 0.00002,
+                        151.259307861 c 0.0,0.0 17.625,-0.207061767578 17.625,-0.207061767578 c 0.0,
+                        0.0 -0.00002,-108.614746094 -0.00002,-111.239746094 c 0.0,-2.625 1.9375,
+                        -2.375 1.9375,-2.375 c 0.0,0.0 175.4375,0.0 177.8125,0.0 c 2.375,0.0 2.125,
+                        2.9375 2.125,2.9375 c 0.0,0.0 0.0,285.8125 0.0,288.125 c 0.0,2.3125 -2.0,
+                        2.0 -2.0,2.0 c 0.0,0.0 -174.875,0.0 -177.6875,0.0 c -2.8125,0.0 -2.3125,
+                        -1.875 -2.3125,-1.875 c 0.0,0.0 0.00005,-86.4319152832 0.00005,
+                        -86.4319152832 c 0.0,0.0 -17.25,0.0 -17.25,0.0 c 0.0,0.0 -0.00005,
+                        121.306915283 -0.00005,132.306915283 c 0.0,11.0 9.25,10.75 9.25,
+                        10.75 c 0.0,0.0 184.25,0.0 195.5,0.0 c 11.25,0.0 10.5,-12.25 10.5,
+                        -12.25 c 0.0,0.0 0.125,-364.75 0.125,-374.5 c 0.0,-9.75 -9.5,-9.5 -9.5,
+                        -9.5 Z"/>
+        </group>
+    </group>
+    <group
+        android:name="arrow"
+        android:scaleX="0.1507"
+        android:scaleY="0.1507"
+        android:translateX="20.86372"
+        android:translateY="33.39034">
+        <group
+            android:name="arrow_pivot"
+            android:translateX="56"
+            android:translateY="-2">
+            <group
+                android:name="shape_2">
+                <path
+                    android:fillColor="#FFFFFFFF"
+                    android:name="path_2"
+                    android:pathData="M -32.2857208252,-52.9642944336 c 0.0,0.0 -15.75,
+                            16.25 -15.75,16.25 c 0.0,0.0 30.3749847412,29.0 30.3749847412,
+                            29.0 c 0.0,0.0 -111.124969482,0.0 -111.124969482,0.0 c 0.0,0.0 0.0,
+                            23.0000152588 0.0,23.0000152588 c 0.0,0.0 110.874938965,
+                            0.0 110.874938965,0.0 c 0.0,0.0 -30.1249542236,29.25 -30.1249542236,
+                            29.25 c 0.0,0.0 16.0,16.0 16.0,16.0 c 0.0,0.0 56.7500152588,
+                            -57.25 56.7500152588,-57.25 c 0.0,0.0 -0.257537841797,
+                            -0.254150390625 -0.257537841797,-0.254150390625 c 0.0,
+                            0.0 -56.742477417,-55.9958648682 -56.742477417,-55.9958648682 Z"/>
+            </group>
+        </group>
+    </group>
+</vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/progress_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/progress_circle.xml
new file mode 100644
index 0000000..2e8d993
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/progress_circle.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorPrimaryDark"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="24.0"
+            android:viewportWidth="24.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M6,2v6h0.01L6,8.01 10,12l-4,4 0.01,0.01H6V22h12v-5.99h-0.01L18,
+                        16l-4,-4 4,-3.99 -0.01,-0.01H18V2H6z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/reply.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/reply.xml
new file mode 100644
index 0000000..72a9569
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/reply.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24dp">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M20,18v-8L6,24l14,14v-8.2c10,0 17,3.2 22,10.2 -2,-10 -8,-20 -22,-22z"/>
+</vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/settings_circle.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/settings_circle.xml
new file mode 100644
index 0000000..e5a70c0
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/settings_circle.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="?android:colorButtonNormal"/>
+            <size
+                android:height="40dp"
+                android:width="40dp"/>
+        </shape>
+    </item>
+    <item
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:viewportHeight="48.0"
+            android:viewportWidth="48.0"
+            android:width="24dp">
+            <path
+                android:fillColor="#FFFFFF"
+                android:pathData="M38.86,25.95c0.08,-0.64 0.14,-1.29 0.14,-1.95s-0.06,-1.31 -0.14,
+                        -1.95l4.23,-3.31c0.38,-0.3 0.49,-0.84 0.24,-1.28l-4,-6.93c-0.25,
+                        -0.43 -0.77,-0.61 -1.22,-0.43l-4.98,2.01c-1.03,-0.79 -2.16,-1.46 -3.38,
+                        -1.97L29,4.84c-0.09,-0.47 -0.5,-0.84 -1,-0.84h-8c-0.5,0 -0.91,0.37 -0.99,
+                        0.84l-0.75,5.3c-1.22,0.51 -2.35,1.17 -3.38,1.97L9.9,10.1c-0.45,-0.17 -0.97,
+                        0 -1.22,0.43l-4,6.93c-0.25,0.43 -0.14,0.97 0.24,1.28l4.22,3.31C9.06,
+                        22.69 9,23.34 9,24s0.06,1.31 0.14,1.95l-4.22,3.31c-0.38,0.3 -0.49,
+                        0.84 -0.24,1.28l4,6.93c0.25,0.43 0.77,0.61 1.22,0.43l4.98,-2.01c1.03,
+                        0.79 2.16,1.46 3.38,1.97l0.75,5.3c0.08,0.47 0.49,0.84 0.99,0.84h8c0.5,
+                        0 0.91,-0.37 0.99,-0.84l0.75,-5.3c1.22,-0.51 2.35,-1.17 3.38,-1.97l4.98,
+                        2.01c0.45,0.17 0.97,0 1.22,-0.43l4,-6.93c0.25,-0.43 0.14,-0.97 -0.24,
+                        -1.28l-4.22,-3.31zM24,31c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,
+                        7 -3.13,7 -7,7z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/start.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/start.xml
new file mode 100644
index 0000000..06d7695
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/start.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24dp">
+    <path android:fillColor="#FFFFFF"
+        android:pathData="M16,10v28l22,-14z"/>
+</vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/stop.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/stop.xml
new file mode 100644
index 0000000..d23c929
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/stop.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24dp">
+    <path android:fillColor="#FFFFFF"
+        android:pathData="M38,12.83L35.17,10 24,21.17 12.83,10 10,12.83 21.17,24 10,
+        35.17 12.83,38 24,26.83 35.17,38 38,35.17 26.83,24z"/>
+</vector>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/watch.png b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/watch.png
new file mode 100644
index 0000000..0ed1b5f
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/drawable/watch.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_accessibility.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_accessibility.xml
new file mode 100644
index 0000000..2760d68
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_accessibility.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scroll_view_accessibility"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_centerHorizontal="true"
+    android:layout_centerVertical="true">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="?android:dialogPreferredPadding"
+        android:paddingBottom="?android:dialogPreferredPadding"
+        android:paddingStart="?android:listPreferredItemPaddingStart"
+        android:paddingEnd="?android:listPreferredItemPaddingEnd"
+        android:orientation="vertical">
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
+            android:text="@string/description_1_accessibility"
+            android:textAppearance="@style/android:TextAppearance.Material.Title"/>
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
+            android:text="@string/description_2_accessibility"
+            android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
+            android:text="@string/description_3_accessibility"
+            android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+        <include
+            android:id="@+id/accessibility_button_include"
+            layout="@layout/app_item_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_dialogs.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_dialogs.xml
new file mode 100644
index 0000000..5c47cb5
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_dialogs.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ListView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/list_view_dialogs"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="?android:dialogPreferredPadding"
+    android:paddingBottom="?android:dialogPreferredPadding"
+    android:clipToPadding="false"/>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_fullscreen_progress.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_fullscreen_progress.xml
new file mode 100644
index 0000000..4b8e443
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_fullscreen_progress.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <ProgressBar
+        android:id="@+id/progressBar"
+        style="?android:attr/progressBarStyleLarge"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"/>
+    <TextView
+        android:id="@+id/loadingTextView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/progressBar"
+        android:layout_centerHorizontal="true"
+        android:paddingTop="8dp"
+        android:text="@string/loading"
+        android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_images.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_images.xml
new file mode 100644
index 0000000..4bcb716
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_images.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scroll_view_tutorial_images"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_centerHorizontal="true"
+    android:layout_centerVertical="true">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="?android:dialogPreferredPadding"
+        android:paddingBottom="?android:dialogPreferredPadding"
+        android:paddingStart="?android:listPreferredItemPaddingStart"
+        android:paddingEnd="?android:listPreferredItemPaddingEnd"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/title_images"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
+            android:gravity="center_horizontal"
+            android:text="@string/images"
+            android:textAppearance="@style/android:TextAppearance.Material.Title"/>
+        <TextView
+            android:id="@+id/description_1_tutorial_image"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
+            android:text="@string/description_1_tutorial_image"
+            android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+        <ImageView
+            android:id="@+id/swipe_left_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
+            android:contentDescription="@string/swipe_left"
+            android:foregroundTint="@color/dark_blue"
+            android:src="@drawable/oobe_swipe_left_long_animation"
+            android:tint="@color/dark_blue"/>
+        <TextView
+            android:id="@+id/description_2_tutorial_image"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:paddingTop="4dp"
+            android:text="@string/description_2_tutorial_image"
+            android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+        <ImageView
+            android:id="@+id/tap_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:contentDescription="@string/tap"
+            android:foregroundTint="@color/dark_blue"
+            android:src="@drawable/oobe_tap_animation"
+            android:tint="@color/dark_blue"/>
+        <TextView
+            android:id="@+id/description_3_tutorial_image"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:paddingBottom="8dp"
+            android:text="@string/description_3_tutorial_image"
+            android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+        <TextView
+            android:id="@+id/description_1_decorative_image"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="8dp"
+            android:paddingBottom="4dp"
+            android:text="@string/description_1_decorative_image"
+            android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+        <ImageView
+            android:id="@+id/bow_image"
+            android:layout_width="match_parent"
+            android:layout_height="75dp"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
+            android:scaleType="centerInside"
+            android:src="@drawable/bow"/>
+        <TextView
+            android:id="@+id/description_2_decorative_image"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
+            android:text="@string/description_2_decorative_image"
+            android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_list_of_graphics.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_list_of_graphics.xml
new file mode 100644
index 0000000..369aee7
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_list_of_graphics.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ListView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/list_view_graphics"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="?android:dialogPreferredPadding"
+    android:paddingBottom="?android:dialogPreferredPadding"
+    android:clickable="true"
+    android:clipToPadding="false"
+    android:divider="@null"
+    android:dividerHeight="0dp"/>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_lists.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_lists.xml
new file mode 100644
index 0000000..111209f
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_lists.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ListView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/list_view_lists"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="?android:dialogPreferredPadding"
+    android:paddingBottom="?android:dialogPreferredPadding"
+    android:clipToPadding="false"/>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_long_list.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_long_list.xml
new file mode 100644
index 0000000..e133f15
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_long_list.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<android.support.wear.widget.drawer.WearableDrawerLayout
+    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/drawer_layout_long_list"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:deviceIds="wear">
+    <android.support.wear.widget.WearableRecyclerView
+        android:id="@+id/recycler_view_long_list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingTop="?android:dialogPreferredPadding"
+        android:paddingBottom="?android:dialogPreferredPadding"
+        android:clipToPadding="false"
+        android:scrollbars="vertical"/>
+    <android.support.wear.widget.drawer.WearableActionDrawerView
+        android:id="@+id/action_drawer_long_list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible"
+        app:actionMenu="@menu/action_drawer_menu"
+        app:show_overflow_in_peek="true">
+    </android.support.wear.widget.drawer.WearableActionDrawerView>
+</android.support.wear.widget.drawer.WearableDrawerLayout>
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_main.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..2144647
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_main.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<android.support.wear.widget.WearableRecyclerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/main_recycler_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_centerHorizontal="true"
+    android:layout_centerVertical="true"
+    android:scrollbars="vertical"/>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_messaging_main.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_messaging_main.xml
new file mode 100644
index 0000000..5577d6f
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_messaging_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/messaging_text_view"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingTop="?android:dialogPreferredPadding"
+    android:paddingBottom="?android:dialogPreferredPadding"
+    android:paddingStart="?android:listPreferredItemPaddingStart"
+    android:paddingEnd="?android:listPreferredItemPaddingEnd"
+    android:text="@string/main_text_activity_messaging_main"/>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_notifications.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_notifications.xml
new file mode 100644
index 0000000..d8476bd
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_notifications.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scroll_view_notifications"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_centerHorizontal="true"
+    android:layout_centerVertical="true">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="?android:dialogPreferredPadding"
+        android:paddingBottom="?android:dialogPreferredPadding"
+        android:paddingStart="?android:listPreferredItemPaddingStart"
+        android:paddingEnd="?android:listPreferredItemPaddingEnd"
+        android:orientation="vertical">
+        <include
+            android:id="@+id/notifications_title_include"
+            layout="@layout/title_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+        <include
+            android:id="@+id/inline_action_switch_include"
+            layout="@layout/switch_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+        <include
+            android:id="@+id/avatar_switch_include"
+            layout="@layout/switch_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+        <include
+            android:id="@+id/push_notification_app_item_include"
+            layout="@layout/app_item_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_open_on_phone_animation.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_open_on_phone_animation.xml
new file mode 100644
index 0000000..887d65d
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_open_on_phone_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<RelativeLayout
+    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"
+    android:paddingTop="?android:dialogPreferredPadding"
+    android:paddingBottom="?android:dialogPreferredPadding"
+    tools:context="com.example.android.wearable.wear.wearaccessibilityapp.OpenOnPhoneAnimationActivity">
+    <ImageView
+        android:id="@+id/open_on_phone_animation_image"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:contentDescription="tap"
+        android:foregroundTint="@color/white"
+        android:src="@drawable/open_on_phone_animation"
+        android:tint="@color/white"/>
+    <TextView
+        android:id="@+id/description_dialogs_phone_animation"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/open_on_phone_animation_image"
+        android:paddingTop="?android:dialogPreferredPadding"
+        android:gravity="center"
+        android:text="@string/continue_on_phone"
+        android:textAppearance="@style/android:TextAppearance.Material.Caption"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_photo_carousel.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_photo_carousel.xml
new file mode 100644
index 0000000..d135ecd
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_photo_carousel.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scroll_view_carousel"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_centerHorizontal="true"
+    android:layout_centerVertical="true">
+    <LinearLayout
+        android:id="@+id/layout_photo_carousel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="?android:dialogPreferredPadding"
+        android:paddingBottom="?android:dialogPreferredPadding"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/title_photo_carousel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:text="@string/photo_carousel"
+            android:textAppearance="@style/android:TextAppearance.Material.Title"/>
+        <ImageView
+            android:id="@+id/cat_image"
+            android:layout_width="100dp"
+            android:layout_height="100dp"
+            android:layout_gravity="center"
+            android:contentDescription="@string/description_of_cat_image"
+            android:src="@drawable/cats"/>
+        <ImageView
+            android:id="@+id/dog_image"
+            android:layout_width="100dp"
+            android:layout_height="100dp"
+            android:layout_gravity="center"
+            android:contentDescription="@string/description_of_dog_image"
+            android:src="@drawable/dog"/>
+        <ImageView
+            android:id="@+id/hamster_image"
+            android:layout_width="100dp"
+            android:layout_height="100dp"
+            android:layout_gravity="center"
+            android:contentDescription="@string/description_of_hamster_image"
+            android:src="@drawable/hamster"/>
+        <ImageView
+            android:id="@+id/bird_image"
+            android:layout_width="100dp"
+            android:layout_height="100dp"
+            android:layout_gravity="center"
+            android:contentDescription="@string/description_of_bird_image"
+            android:src="@drawable/birds"/>
+        <TextView
+            android:id="@+id/description_photo_carousel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingStart="?android:listPreferredItemPaddingStart"
+            android:paddingEnd="?android:listPreferredItemPaddingEnd"
+            android:text="@string/graphics_description"
+            android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_radio_list.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_radio_list.xml
new file mode 100644
index 0000000..47a5472
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_radio_list.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_centerHorizontal="true"
+    android:layout_centerVertical="true"
+    android:paddingTop="?android:dialogPreferredPadding">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <include
+            android:id="@+id/radio_list_title"
+            layout="@layout/title_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+        <RadioGroup
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:paddingStart="?android:listPreferredItemPaddingStart"
+            android:paddingEnd="?android:listPreferredItemPaddingEnd">
+            <RadioButton
+                android:id="@+id/radio_button_1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/android:TextAppearance.Material.Body1"
+                android:padding="4dp"
+                android:text="@string/hello"/>
+            <RadioButton
+                android:id="@+id/radio_button_2"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/android:TextAppearance.Material.Body1"
+                android:padding="4dp"
+                android:text="@string/hi"/>
+            <RadioButton
+                android:id="@+id/radio_button_3"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/android:TextAppearance.Material.Body1"
+                android:padding="4dp"
+                android:text="@string/howdy"/>
+        </RadioGroup>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_zoom_image.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_zoom_image.xml
new file mode 100644
index 0000000..72d5a8a
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/activity_zoom_image.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/expanded_image"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:contentDescription="@string/description_of_cat_image"
+    android:scaleType="centerInside"
+    android:src="@drawable/cats"/>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/app_item_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/app_item_layout.xml
new file mode 100644
index 0000000..c313a46
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/app_item_layout.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="4dp"
+    android:paddingEnd="?android:listPreferredItemPaddingEnd">
+    <ImageView
+        android:id="@+id/icon_image_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_view_list_white_1x_web_48dp"/>
+    <TextView
+        android:id="@+id/icon_text_view"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginStart="8dp"
+        android:gravity="center_vertical"
+        android:text="@string/default_text"
+        android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/circled_image_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/circled_image_layout.xml
new file mode 100644
index 0000000..d28ac0d
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/circled_image_layout.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/rounded_drawable_layout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+  <android.support.wearable.view.CircledImageView
+      android:id="@+id/circled_image_view"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_marginStart="?android:listPreferredItemPaddingStart"
+      app:circle_border_color="?android:colorAccent"
+      app:circle_border_width="4dp"
+      app:circle_color="@color/icon_color"
+      app:circle_radius="18dp"/>
+  <TextView
+      android:id="@+id/circled_image_text"
+      android:layout_width="wrap_content"
+      android:layout_height="match_parent"
+      android:gravity="center_vertical"
+      android:layout_marginStart="8dp"
+      android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/header_footer_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/header_footer_layout.xml
new file mode 100644
index 0000000..f47f428
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/header_footer_layout.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="?android:dialogPreferredPadding"/>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/list_item_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/list_item_layout.xml
new file mode 100644
index 0000000..fe0d169
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/list_item_layout.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="48dp"
+    android:gravity="center_vertical"
+    android:padding="4dp"
+    android:paddingStart="?android:listPreferredItemPaddingStart"
+    android:paddingEnd="?android:listPreferredItemPaddingEnd">
+    <TextView
+        android:id="@+id/item_text"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:text="@string/default_text"
+        android:textAppearance="@style/android:TextAppearance.Material.Title"/>
+    <ImageView
+        android:id="@+id/item_image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:src="@drawable/arrow"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/long_list_switch_widget_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/long_list_switch_widget_layout.xml
new file mode 100644
index 0000000..872469f
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/long_list_switch_widget_layout.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="4dp"
+    android:paddingStart="?android:listPreferredItemPaddingStart"
+    android:paddingEnd="?android:listPreferredItemPaddingEnd">
+    <Switch
+        android:id="@+id/switch_widget"
+        style="@style/Widget.Wear.RoundSwitch"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true"
+        android:checked="false">
+    </Switch>
+    <TextView
+        android:id="@+id/switch_text"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginLeft="10dp"
+        android:layout_centerVertical="true"
+        android:layout_toRightOf="@id/switch_widget"
+        android:gravity="center_vertical"
+        android:text="@string/default_text"
+        android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/progress_bar_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/progress_bar_layout.xml
new file mode 100644
index 0000000..d30889b
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/progress_bar_layout.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<ProgressBar
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/progress_bar_long_list"
+    style="?android:attr/progressBarStyle"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal"/>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/progress_bar_with_text_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/progress_bar_with_text_layout.xml
new file mode 100644
index 0000000..21180e6
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/progress_bar_with_text_layout.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/progress_bar_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="4dp">
+    <ProgressBar
+        android:id="@+id/progress_bar"
+        style="?android:attr/progressBarStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="?android:listPreferredItemPaddingStart"/>
+    <TextView
+        android:id="@+id/progress_bar_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/indeterminant_progress"
+        android:layout_marginStart="8dp"
+        android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/shifted_app_item_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/shifted_app_item_layout.xml
new file mode 100644
index 0000000..576ea10
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/shifted_app_item_layout.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="4dp"
+    android:paddingStart="?android:listPreferredItemPaddingStart"
+    android:paddingEnd="?android:listPreferredItemPaddingEnd">
+    <ImageView
+        android:id="@+id/shifted_icon_image_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_view_list_white_1x_web_48dp"/>
+    <TextView
+        android:id="@+id/shifted_icon_text_view"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginStart="8dp"
+        android:gravity="center_vertical"
+        android:text="@string/default_text"
+        android:textAppearance="@style/android:TextAppearance.Material.Body1"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/switch_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/switch_layout.xml
new file mode 100644
index 0000000..b1c751c
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/switch_layout.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/switch_widget_layout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="4dp">
+    <Switch
+        android:id="@+id/switch_widget"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:checked="true"
+        android:layout_marginStart="?android:listPreferredItemPaddingStart"
+        android:clickable="false">
+    </Switch>
+    <TextView
+        android:id="@+id/switch_text"
+        android:text="@string/switch_name"
+        android:textAppearance="@style/android:TextAppearance.Material.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/title_layout.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/title_layout.xml
new file mode 100644
index 0000000..e3383f9
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/layout/title_layout.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/title_text"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="4dp"
+    android:text="@string/default_text"
+    android:gravity="center_horizontal"
+    android:textAppearance="@style/android:TextAppearance.Material.Title"/>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/menu/action_drawer_menu.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/menu/action_drawer_menu.xml
new file mode 100644
index 0000000..ccc517e
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/menu/action_drawer_menu.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent">
+    <item
+        android:id="@+id/menu_click_hold"
+        android:icon="@drawable/heart"
+        android:title="@string/action_1"/>
+    <item
+        android:id="@+id/menu_right_click"
+        android:icon="@drawable/heart"
+        android:title="@string/action_2"/>
+    <item
+        android:id="@+id/menu_exit"
+        android:icon="@drawable/heart"
+        android:title="@string/action_3"/>
+</menu>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/values/colors.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/values/colors.xml
new file mode 100644
index 0000000..ffe1e49
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <color name="background">#44104d</color>
+    <color name="accent">#ec80ff</color>
+    <color name="icon_color">#9c27b0</color>
+    <color name="dialog_icon">#7f7f7f</color>
+</resources>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/values/strings.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/values/strings.xml
new file mode 100644
index 0000000..818cf0c
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/values/strings.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <string name="app_name">Wear Accessibility App</string>
+
+    <!-- Strings for Lists -->
+    <string name="lists">Lists</string>
+    <string name="description_2_tutorial_image">Swipe hint is labeled \"swipe left\"</string>
+    <string name="description_3_tutorial_image">Tap hint labeled \"tap\"</string>
+    <string name="description_1_decorative_image">Graphics that are used decoratively that do
+            not add additional meaning do not need a text label.</string>
+    <string name="description_2_decorative_image">Bow graphic is unlabeled and would be passed
+            over by a screen reader.</string>
+    <string name="a_long_list">A long list</string>
+    <string name="list_of_graphics">List of graphics</string>
+    <string name="bottom_action_drawer">Bottom action \ndrawer</string>
+    <string name="photo_carousel">Photo carousel</string>
+    <string name="images">Images</string>
+    <string name="graphics_description">
+            Each image has a descriptive label for a screenreader.</string>
+    <string name="description_of_cat_image">Two cats forming a heart.</string>
+    <string name="description_of_dog_image">Dog holding a bone.</string>
+    <string name="description_of_hamster_image">Hamster hugging a baby carrot.</string>
+    <string name="description_of_bird_image">Two love birds on a branch.</string>
+    <string name="zoom_image">Zoomed Image</string>
+    <string name="intent_extra_image">image</string>
+    <string name="description_1_tutorial_image">Graphics that add additional information should
+            be properly labeled.</string>
+    <string name="swipe_left">swipe left</string>
+    <string name="action_1">Action 1</string>
+    <string name="action_2">Action 2</string>
+    <string name="action_3">Action 3</string>
+    <string name="item_text">Item %1$d</string>
+    <string name="switch_bottom_action_drawer">%1$s Switch Bottom Action Drawer</string>
+    <string name="on">On</string>
+    <string name="off">Off</string>
+
+    <!-- Strings for Dialogs -->
+    <string name="dialogs">Dialogs</string>
+    <string name="open_on_phone_animation">Open On Phone Animation</string>
+    <string name="yes_no_dialog">Yes/no dialog</string>
+    <string name="yes_no_dialog_description">This dialog only has two actions available.</string>
+    <string name="one_action_dialog">One action dialog</string>
+    <string name="one_action_dialog_description">There is only one action on this dialog.</string>
+    <string name="multiple_action_dialog">Multiple action dialog</string>
+    <string name="multiple_action_dialog_description">This dialog has multiple actions.</string>
+    <string name="ok">OK</string>
+    <string name="close">Close</string>
+    <string name="open_on_phone">Open on phone</string>
+    <string name="yes_no_action">Yes/No action</string>
+    <string name="one_action">One action</string>
+    <string name="multiple_actions">Multiple actions</string>
+    <string name="continue_on_phone">Continue on phone</string>
+    <string name="tap">tap</string>
+
+    <!-- Strings for Progress -->
+    <string name="progress">Progress</string>
+    <string name="in_line">In-line</string>
+    <string name="full_screen">Full screen</string>
+    <string name="loading">Loading&#8230;</string>
+    <string name="start">Start</string>
+    <string name="determinant">Determinant</string>
+    <string name="in_line_progress">In-line Progress</string>
+    <string name="indeterminant_progress">Indeterminant\nProgress</string>
+    <string name="key_pref_determinant_switch">pref_determinant_switch</string>
+    <string name="key_pref_circled_image_view">pref_circled_image_view</string>
+    <string name="key_pref_progress_screen">pref_progress_screen</string>
+
+    <!-- Strings for Controls -->
+    <string name="controls">Controls</string>
+    <string name="checkbox">Checkbox</string>
+    <string name="radio_list">Radio List</string>
+    <string name="switch_name">Switch</string>
+    <string name="hello">Hello</string>
+    <string name="hi">Hi</string>
+    <string name="howdy">Howdy</string>
+    <string name="radio_button_list">Radio Button List</string>
+
+    <!-- Strings for Notifications -->
+    <string name="notifications">Notifications</string>
+    <string name="main_text_activity_messaging_main">
+            This Activity would handle the messaging app\'s functionality for a chat(s).
+            \n\nThe notification type for this example was the Messaging Style!
+    </string>
+    <string name="reply_label">Reply</string>
+    <string name="inline_action">In-line action</string>
+    <string name="avatar">Avatar</string>
+    <string name="push_notification">Push notification now</string>
+    <string name="key_pref_avatar">pref_avatar</string>
+    <string name="key_pref_action">pref_action</string>
+    <string name="key_pref_push_notification">pref_push_notification</string>
+
+    <!-- Strings for Accessibility -->
+    <string name="description_1_accessibility">
+            Make sure your watch is accessible for all users</string>
+    <string name="description_2_accessibility">
+            What does your app look like in the largest text size?</string>
+    <string name="description_3_accessibility">Does your app work with a screen reader?</string>
+    <string name="accessibility">Accessibility</string>
+    <string name="accessibility_settings">Accessibility settings</string>
+
+    <string name="default_text">TextView</string>
+    <string name="title">title</string>
+</resources>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/values/styles.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/values/styles.xml
new file mode 100644
index 0000000..4b49a6e
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/values/styles.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <style name="SampleAppTheme" parent="android:Theme.Material.NoActionBar">
+        <item name="android:colorBackground">@color/background</item>
+        <item name="android:colorAccent">@color/accent</item>
+        <!-- Used for border of radio buttons and checkboxes -->
+        <item name="android:textColorSecondary">@color/icon_color</item>
+        <!-- Used for icon's background color -->
+        <item name="android:colorPrimaryDark">@color/icon_color</item>
+        <!-- Used for action drawer's background color -->
+        <item name="android:colorBackgroundFloating">@color/icon_color</item>
+        <!-- Used for dialog's deny buttons -->
+        <item name="android:colorButtonNormal">@color/dialog_icon</item>
+        <!-- Used for switch widget's background color -->
+        <item name="android:colorPrimary">@color/semitransparent_grey</item>
+    </style>
+    <style name="OpenOnPhoneAnimationTheme" parent="android:Theme.Material.NoActionBar">
+        <item name="android:colorBackground">@color/black</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/xml/prefs_controls.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/xml/prefs_controls.xml
new file mode 100644
index 0000000..347358f
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/xml/prefs_controls.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/controls">
+    <SwitchPreference
+        android:key="pref_switch"
+        android:title="@string/switch_name"/>
+    <CheckBoxPreference
+        android:key="pref_checkbox"
+        android:title="@string/checkbox"/>
+    <Preference
+        android:key="pref_radio_button_list"
+        android:title="@string/radio_button_list"
+        android:icon="@drawable/arrow_circle">
+        <intent
+            android:targetPackage="com.example.android.wearable.wear.wearaccessibilityapp"
+            android:targetClass="com.example.android.wearable.wear.wearaccessibilityapp.RadioListActivity"/>
+    </Preference>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/xml/prefs_in_line_progress.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/xml/prefs_in_line_progress.xml
new file mode 100644
index 0000000..9b5842e
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/xml/prefs_in_line_progress.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="pref_progress_screen"
+    android:title="@string/in_line_progress">
+    <SwitchPreference
+        android:key="pref_determinant_switch"
+        android:title="@string/determinant"/>
+    <com.example.android.wearable.wear.wearaccessibilityapp.CircledImageViewPreference
+        android:key="pref_circled_image_view"
+        android:title="@string/start"/>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/xml/prefs_notifications.xml b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/xml/prefs_notifications.xml
new file mode 100644
index 0000000..9aa2f5c
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/Wearable/src/main/res/xml/prefs_notifications.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/notifications">
+    <SwitchPreference
+        android:key="pref_action"
+        android:title="@string/inline_action"/>
+    <SwitchPreference
+        android:key="pref_avatar"
+        android:title="@string/avatar"/>
+    <Preference
+        android:key="pref_push_notification"
+        android:title="@string/push_notification"
+        android:icon="@drawable/arrow_circle"/>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/wearable/wear/WearAccessibilityApp/build.gradle b/wearable/wear/WearAccessibilityApp/build.gradle
new file mode 100644
index 0000000..b95a860
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/build.gradle
@@ -0,0 +1,12 @@
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+  pathToBuild "../../../../../build"
+  pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/wearable/wear/WearAccessibilityApp/buildSrc/build.gradle b/wearable/wear/WearAccessibilityApp/buildSrc/build.gradle
new file mode 100644
index 0000000..7c150e4
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/buildSrc/build.gradle
@@ -0,0 +1,16 @@
+
+repositories {
+    jcenter()
+}
+dependencies {
+    compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+    main {
+        groovy {
+            srcDir new File(rootDir, "../../../../../../build/buildSrc/src/main/groovy")
+        }
+    }
+}
+
diff --git a/wearable/wear/WearAccessibilityApp/gradle/wrapper/gradle-wrapper.jar b/wearable/wear/WearAccessibilityApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WearAccessibilityApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..9470ad8
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
+
diff --git a/wearable/wear/WearAccessibilityApp/gradlew b/wearable/wear/WearAccessibilityApp/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/wearable/wear/WearAccessibilityApp/gradlew.bat b/wearable/wear/WearAccessibilityApp/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windowz variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+if "%@eval[2+2]" == "4" goto 4NT_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+goto execute

+

+:4NT_args

+@rem Get arguments from the 4NT Shell from JP Software

+set CMD_LINE_ARGS=%$

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/wearable/wear/WearAccessibilityApp/screenshots/controls_screen.png b/wearable/wear/WearAccessibilityApp/screenshots/controls_screen.png
new file mode 100644
index 0000000..2363dc5
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/screenshots/controls_screen.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/screenshots/main_screen.png b/wearable/wear/WearAccessibilityApp/screenshots/main_screen.png
new file mode 100644
index 0000000..ecd58bc
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/screenshots/main_screen.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/screenshots/progress_screen.png b/wearable/wear/WearAccessibilityApp/screenshots/progress_screen.png
new file mode 100644
index 0000000..7067489
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/screenshots/progress_screen.png
Binary files differ
diff --git a/wearable/wear/WearAccessibilityApp/settings.gradle b/wearable/wear/WearAccessibilityApp/settings.gradle
new file mode 100644
index 0000000..9c2651c
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/settings.gradle
@@ -0,0 +1,2 @@
+
+include ':Wearable'
diff --git a/wearable/wear/WearAccessibilityApp/template-params.xml b/wearable/wear/WearAccessibilityApp/template-params.xml
new file mode 100644
index 0000000..7117644
--- /dev/null
+++ b/wearable/wear/WearAccessibilityApp/template-params.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<sample>
+    <name>WearAccessibilityApp</name>
+    <group>Wearable</group>
+    <package>com.example.android.wearable.wear.wearaccessibilityapp</package>
+
+    <minSdkVersionWear>24</minSdkVersionWear>
+    <compileSdkVersionWear>26</compileSdkVersionWear>
+    <targetSdkVersionWear>26</targetSdkVersionWear>
+
+    <multiDexEnabled>true</multiDexEnabled>
+
+    <dependency_wearable>com.android.support:wear:27.1.0</dependency_wearable>
+    <dependency_wearable>com.android.support.constraint:constraint-layout:1.0.2</dependency_wearable>
+    <dependency_wearable>com.android.support:appcompat-v7:27.1.0</dependency_wearable>
+
+
+    <strings>
+        <intro>
+            <![CDATA[
+            Sample demostrates best practices for accessibility (a11y support).
+            ]]>
+        </intro>
+    </strings>
+
+    <template src="base-build" />
+    <template src="Wear" />
+
+    <metadata>
+        <!-- Values: {DRAFT | PUBLISHED | INTERNAL | DEPRECATED | SUPERCEDED} -->
+        <status>PUBLISHED</status>
+        <!-- See http://go/sample-categories for details on the next 4 fields. -->
+        <!-- Most samples just need to udpate the Categories field. This is a comma-
+             seperated list of topic tags. Unlike the old category system, samples
+             may have multiple categories, so feel free to add extras. Try to avoid
+             simply tagging everything with "UI". :)-->
+        <categories>Wearable</categories>
+        <technologies>Android</technologies>
+        <languages>Java</languages>
+        <solutions>Mobile</solutions>
+        <!-- Values: {BEGINNER | INTERMEDIATE | ADVANCED | EXPERT} -->
+        <!-- Beginner is for "getting started" type content, or essential content.
+             (e.g. "Hello World", activities, intents)
+
+             Intermediate is for content that covers material a beginner doesn't need
+             to know, but that a skilled developer is expected to know.
+             (e.g. services, basic styles and theming, sync adapters)
+
+             Advanced is for highly technical content geared towards experienced developers.
+             (e.g. performance optimizations, custom views, bluetooth)
+
+             Expert is reserved for highly technical or specialized content, and should
+             be used sparingly. (e.g. VPN clients, SELinux, custom instrumentation runners) -->
+        <level>INTERMEDIATE</level>
+        <!-- Dimensions: 512x512, PNG fomrat -->
+        <icon>screenshots/icon-web.png</icon>
+        <!-- Path to screenshots. Use <img> tags for each. -->
+        <screenshots>
+            <img>screenshots/main_screen.png</img>
+            <img>screenshots/progress_screen.png</img>
+            <img>screenshots/controls_screen.png</img>
+        </screenshots>
+        <!-- List of APIs that this sample should be cross-referenced under. Use <android>
+        for fully-qualified Framework class names ("android:" namespace).
+
+        Use <ext> for custom namespaces, if needed. See "Samples Index API" documentation
+        for more details. -->
+        <api_refs>
+            <android>android.support.wear.widget.WearableRecyclerView</android>
+            <android>android.preference.Preference</android>
+            <android>android.support.v4.app.NotificationCompat</android>
+        </api_refs>
+
+        <!-- 1-3 line description of the sample here.
+
+            Avoid simply rearranging the sample's title. What does this sample actually
+            accomplish, and how does it do it? -->
+        <description>
+            Sample demonstrates how to include accessibility support for your wearable app.
+        </description>
+
+        <!-- Multi-paragraph introduction to sample, from an educational point-of-view.
+        Makrdown formatting allowed. This will be used to generate a mini-article for the
+        sample on DAC. -->
+        <intro>
+            Accessibility is an important part of any app (especially wearable apps). By
+            integrating accessible components and services, you can improve your app's usability,
+            particularly for users with disabilities.
+
+            This sample demonstrates common UX patterns in wearable apps along with accessibility
+            support of those patterns. Be sure to review the [Accessibility Developer Checklist][1]
+            for your own app. For additional information please see our
+            [Best Practices for User Interface][2] page.
+
+            [1]: https://developer.android.com/guide/topics/ui/accessibility/checklist.html
+            [2]: https://developer.android.com/training/accessibility/index.html
+        </intro>
+    </metadata>
+</sample>
diff --git a/wearable/wear/WearComplicationProvidersTestSuite/Wearable/build.gradle b/wearable/wear/WearComplicationProvidersTestSuite/Wearable/build.gradle
index 748a936..84288bb 100644
--- a/wearable/wear/WearComplicationProvidersTestSuite/Wearable/build.gradle
+++ b/wearable/wear/WearComplicationProvidersTestSuite/Wearable/build.gradle
@@ -2,10 +2,11 @@
 buildscript {
     repositories {
         jcenter()
+        google()
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.1'
     }
 }
 
@@ -13,24 +14,22 @@
 
 repositories {
     jcenter()
-    maven {
-        url 'https://maven.google.com'
-    }
+    google()
 }
 
 
 
 dependencies {
 
-    compile 'com.android.support:appcompat-v7:26.0.0'
+    compile 'com.android.support:appcompat-v7:27.1.0'
 
 
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile 'com.google.android.gms:play-services-wearable:11.8.0'
+    compile 'com.android.support:support-v13:27.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.3.0'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.3.0'
 
 }
 
@@ -44,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 26
+    compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "27.0.3"
 
     defaultConfig {
         versionCode 1
diff --git a/wearable/wear/WearComplicationProvidersTestSuite/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WearComplicationProvidersTestSuite/gradle/wrapper/gradle-wrapper.properties
index c6f7cd0..c9f6185 100644
--- a/wearable/wear/WearComplicationProvidersTestSuite/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/WearComplicationProvidersTestSuite/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/wearable/wear/WearComplicationProvidersTestSuite/template-params.xml b/wearable/wear/WearComplicationProvidersTestSuite/template-params.xml
index 91b86c1..9270990 100644
--- a/wearable/wear/WearComplicationProvidersTestSuite/template-params.xml
+++ b/wearable/wear/WearComplicationProvidersTestSuite/template-params.xml
@@ -20,7 +20,7 @@
     <package>com.example.android.wearable.wear.wearcomplicationproviderstestsuite</package>
 
     <minSdk>18</minSdk>
-    <targetSdkVersion>25</targetSdkVersion>
+    <targetSdkVersion>27</targetSdkVersion>
 
     <minSdkVersionWear>23</minSdkVersionWear>
     <compileSdkVersionWear>26</compileSdkVersionWear>
@@ -30,7 +30,7 @@
         <has_handheld_app>false</has_handheld_app>
     </wearable>
 
-    <dependency_wearable>com.android.support:appcompat-v7:26.0.0</dependency_wearable>
+    <dependency_wearable>com.android.support:appcompat-v7:27.1.0</dependency_wearable>
 
     <strings>
         <intro>
@@ -43,7 +43,7 @@
 
     <template src="base-build" />
     <template src="Wear" />
-    
+
     <metadata>
         <!-- Values: {DRAFT | PUBLISHED | INTERNAL | DEPRECATED | SUPERCEDED} -->
         <status>PUBLISHED</status>
diff --git a/wearable/wear/WearDrawers/Wearable/build.gradle b/wearable/wear/WearDrawers/Wearable/build.gradle
index 332123f..6a22d1c 100644
--- a/wearable/wear/WearDrawers/Wearable/build.gradle
+++ b/wearable/wear/WearDrawers/Wearable/build.gradle
@@ -2,10 +2,11 @@
 buildscript {
     repositories {
         jcenter()
+        google()
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.1'
     }
 }
 
@@ -13,24 +14,22 @@
 
 repositories {
     jcenter()
-    maven {
-        url 'https://maven.google.com'
-    }
+    google()
 }
 
 
 
 dependencies {
 
-    compile 'com.android.support:wear:26.0.0'
+    compile 'com.android.support:wear:27.1.0'
 
 
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile 'com.google.android.gms:play-services-wearable:11.8.0'
+    compile 'com.android.support:support-v13:27.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.3.0'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.3.0'
 
 }
 
@@ -44,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 26
+    compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "27.0.3"
 
     defaultConfig {
         versionCode 1
diff --git a/wearable/wear/WearDrawers/Wearable/src/main/java/com/example/android/wearable/wear/weardrawers/MainActivity.java b/wearable/wear/WearDrawers/Wearable/src/main/java/com/example/android/wearable/wear/weardrawers/MainActivity.java
index da46dc3..c90583b 100644
--- a/wearable/wear/WearDrawers/Wearable/src/main/java/com/example/android/wearable/wear/weardrawers/MainActivity.java
+++ b/wearable/wear/WearDrawers/Wearable/src/main/java/com/example/android/wearable/wear/weardrawers/MainActivity.java
@@ -15,14 +15,18 @@
  */
 package com.example.android.wearable.wear.weardrawers;
 
+import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.content.Context;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.support.wear.ambient.AmbientMode;
 import android.support.wear.widget.drawer.WearableActionDrawerView;
 import android.support.wear.widget.drawer.WearableNavigationDrawerView;
-import android.support.wearable.activity.WearableActivity;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
@@ -34,10 +38,12 @@
 import java.util.ArrayList;
 
 /**
- * Demonstrates use of Navigation and Action Drawers on Android Wear.
+ * Demonstrates use of Navigation and Action Drawers on Wear.
  */
-public class MainActivity extends WearableActivity implements
-        MenuItem.OnMenuItemClickListener, WearableNavigationDrawerView.OnItemSelectedListener {
+public class MainActivity extends Activity implements
+        AmbientMode.AmbientCallbackProvider,
+        MenuItem.OnMenuItemClickListener,
+        WearableNavigationDrawerView.OnItemSelectedListener {
 
     private static final String TAG = "MainActivity";
 
@@ -55,7 +61,9 @@
         Log.d(TAG, "onCreate()");
 
         setContentView(R.layout.activity_main);
-        setAmbientEnabled();
+
+        // Enables Ambient mode.
+        AmbientMode.attachAmbientSupport(this);
 
         mSolarSystem = initializeSolarSystem();
         mSelectedPlanet = 0;
@@ -204,6 +212,7 @@
         public static final String ARG_PLANET_IMAGE_ID = "planet_image_id";
 
         private ImageView mImageView;
+        private ColorFilter mImageViewColorFilter;
 
         public PlanetFragment() {
             // Empty constructor required for fragment subclasses
@@ -219,11 +228,59 @@
             int imageIdToLoad = getArguments().getInt(ARG_PLANET_IMAGE_ID);
             mImageView.setImageResource(imageIdToLoad);
 
+            mImageViewColorFilter = mImageView.getColorFilter();
+
             return rootView;
         }
 
         public void updatePlanet(int imageId) {
             mImageView.setImageResource(imageId);
         }
+
+        public void onEnterAmbientInFragment(Bundle ambientDetails) {
+            Log.d(TAG, "PlanetFragment.onEnterAmbient() " + ambientDetails);
+
+            // Convert image to grayscale for ambient mode.
+            ColorMatrix matrix = new ColorMatrix();
+            matrix.setSaturation(0);
+
+            ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
+            mImageView.setColorFilter(filter);
+        }
+
+        /** Restores the UI to active (non-ambient) mode. */
+        public void onExitAmbientInFragment() {
+            Log.d(TAG, "PlanetFragment.onExitAmbient()");
+
+            mImageView.setColorFilter(mImageViewColorFilter);
+        }
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {
+        /** Prepares the UI for ambient mode. */
+        @Override
+        public void onEnterAmbient(Bundle ambientDetails) {
+            super.onEnterAmbient(ambientDetails);
+            Log.d(TAG, "onEnterAmbient() " + ambientDetails);
+
+            mPlanetFragment.onEnterAmbientInFragment(ambientDetails);
+            mWearableNavigationDrawer.getController().closeDrawer();
+            mWearableActionDrawer.getController().closeDrawer();
+        }
+
+        /** Restores the UI to active (non-ambient) mode. */
+        @Override
+        public void onExitAmbient() {
+            super.onExitAmbient();
+            Log.d(TAG, "onExitAmbient()");
+
+            mPlanetFragment.onExitAmbientInFragment();
+            mWearableActionDrawer.getController().peekDrawer();
+        }
     }
 }
\ No newline at end of file
diff --git a/wearable/wear/WearDrawers/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WearDrawers/gradle/wrapper/gradle-wrapper.properties
index 84a8566..a227e66 100644
--- a/wearable/wear/WearDrawers/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/WearDrawers/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/wearable/wear/WearDrawers/template-params.xml b/wearable/wear/WearDrawers/template-params.xml
index ee02d21..4b8ccdf 100644
--- a/wearable/wear/WearDrawers/template-params.xml
+++ b/wearable/wear/WearDrawers/template-params.xml
@@ -26,7 +26,7 @@
 
     <multiDexEnabled>true</multiDexEnabled>
 
-    <dependency_wearable>com.android.support:wear:26.0.0</dependency_wearable>
+    <dependency_wearable>com.android.support:wear:27.1.0</dependency_wearable>
 
     <strings>
         <intro>
@@ -83,8 +83,8 @@
             If installed on a phone, it will not be automatically pushed to a paired Wear
             device, see [here][2] for more info).
 
-            This sample uses the planets in our solar system to demonstrate the two Android Wear
-            drawer components and concepts relating to [Android Wear][1] and [Material Design][3]:
+            This sample uses the planets in our solar system to demonstrate the two Wear
+            drawer components and concepts relating to [Wear][1] and [Material Design][3]:
             * Customizes and enables screen/planet changes with the [Navigation Drawer][4]
             * Adds customized actions to each screen using the [Action Drawer][5]
 
diff --git a/wearable/wear/WearHighBandwidthNetworking/Wearable/build.gradle b/wearable/wear/WearHighBandwidthNetworking/Wearable/build.gradle
index 45663ff..c56f3a1 100644
--- a/wearable/wear/WearHighBandwidthNetworking/Wearable/build.gradle
+++ b/wearable/wear/WearHighBandwidthNetworking/Wearable/build.gradle
@@ -2,10 +2,11 @@
 buildscript {
     repositories {
         jcenter()
+        google()
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.1'
     }
 }
 
@@ -13,24 +14,22 @@
 
 repositories {
     jcenter()
-    maven {
-        url 'https://maven.google.com'
-    }
+    google()
 }
 
 
 
 dependencies {
 
-    compile 'com.android.support:wear:26.0.0'
+    compile 'com.android.support:wear:27.1.0'
 
 
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile 'com.google.android.gms:play-services-wearable:11.8.0'
+    compile 'com.android.support:support-v13:27.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.3.0'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.3.0'
 
 }
 
@@ -44,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 26
+    compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "27.0.3"
 
     defaultConfig {
         versionCode 1
diff --git a/wearable/wear/WearHighBandwidthNetworking/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WearHighBandwidthNetworking/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..86fc139 100644
--- a/wearable/wear/WearHighBandwidthNetworking/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/WearHighBandwidthNetworking/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/WearHighBandwidthNetworking/template-params.xml b/wearable/wear/WearHighBandwidthNetworking/template-params.xml
index e50f539..5648a3e 100644
--- a/wearable/wear/WearHighBandwidthNetworking/template-params.xml
+++ b/wearable/wear/WearHighBandwidthNetworking/template-params.xml
@@ -31,7 +31,7 @@
 
     <!-- Include additional dependencies here.-->
     <!-- dependency>com.google.android.gms:play-services:5.0.+</dependency -->
-    <dependency_wearable>com.android.support:wear:26.0.0</dependency_wearable>
+    <dependency_wearable>com.android.support:wear:27.1.0</dependency_wearable>
 
 
     <strings>
@@ -111,8 +111,8 @@
         sample on DAC. -->
         <intro>
             <![CDATA[
-On Android Wear, a high-bandwidth network is not always available, as the platform manages network
-connectivity with the goal of providing the best overall user experience, balancing network
+On Wear, a high-bandwidth network is not always available, as the platform manages
+network connectivity with the goal of providing the best overall user experience, balancing network
 bandwidth and maximizing device battery life. For use cases that require high-bandwidth network
 access, such as transporting large files or streaming media, we recommend that apps:
 
diff --git a/wearable/wear/WearMessagingApp/Wearable/build.gradle b/wearable/wear/WearMessagingApp/Wearable/build.gradle
index 1a0d3d1..5e85e8c 100644
--- a/wearable/wear/WearMessagingApp/Wearable/build.gradle
+++ b/wearable/wear/WearMessagingApp/Wearable/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
     }
 }
 
diff --git a/wearable/wear/WearMessagingApp/Wearable/src/main/AndroidManifest.xml b/wearable/wear/WearMessagingApp/Wearable/src/main/AndroidManifest.xml
index f7c11c4..09c5c41 100644
--- a/wearable/wear/WearMessagingApp/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/WearMessagingApp/Wearable/src/main/AndroidManifest.xml
@@ -37,7 +37,7 @@
             android:required="false" />
 
         <!--
-        Important Note: When you have a local/native Android Wear app that creates it's own
+        Important Note: When you have a local/native Wear app that creates it's own
         notifications, you will want to disable the bridge to the phone.
         -->
         <meta-data
diff --git a/wearable/wear/WearMessagingApp/build.gradle b/wearable/wear/WearMessagingApp/build.gradle
index df8f835..842cec5 100644
--- a/wearable/wear/WearMessagingApp/build.gradle
+++ b/wearable/wear/WearMessagingApp/build.gradle
@@ -15,10 +15,11 @@
 buildscript {
   repositories {
     jcenter()
+    google()
   }
 
   dependencies {
-    classpath 'com.android.tools.build:gradle:2.3.3'
+    classpath 'com.android.tools.build:gradle:3.0.0'
     classpath 'com.google.gms:google-services:3.0.0'
   }
 }
@@ -26,5 +27,6 @@
 allprojects {
   repositories {
     jcenter()
+    google()
   }
 }
\ No newline at end of file
diff --git a/wearable/wear/WearMessagingApp/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WearMessagingApp/gradle/wrapper/gradle-wrapper.properties
index 9fca6ff..eee1f3d 100644
--- a/wearable/wear/WearMessagingApp/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/WearMessagingApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/WearMessagingApp/template-params.xml b/wearable/wear/WearMessagingApp/template-params.xml
index af0183a..4cfc428 100644
--- a/wearable/wear/WearMessagingApp/template-params.xml
+++ b/wearable/wear/WearMessagingApp/template-params.xml
@@ -37,7 +37,7 @@
     <strings>
         <intro>
 <![CDATA[
-Sample demonstrates best practices for building a messaging experience on Android Wear.
+Sample demonstrates best practices for building a messaging experience on Wear.
 ]]>
         </intro>
     </strings>
@@ -153,9 +153,9 @@
     the mock database.
 
 
-To see other examples of Google Sign-in, check out the [Android Wear Google Sign-In Sample][1].
+To see other examples of Google Sign-in, check out the [Wear Google Sign-In Sample][1].
 
-To see other examples of notifications, check out the [Android WearNotifications Sample][2]
+To see other examples of notifications, check out the [WearNotifications Sample][2]
 
 [1]: https://github.com/googlesamples/android-WearStandaloneGoogleSignIn
 [2]: https://github.com/googlesamples/android-WearNotifications
diff --git a/wearable/wear/WearNotifications/Application/src/main/java/com/example/android/wearable/wear/wearnotifications/MainActivity.java b/wearable/wear/WearNotifications/Application/src/main/java/com/example/android/wearable/wear/wearnotifications/MainActivity.java
index ec7e188..d944100 100644
--- a/wearable/wear/WearNotifications/Application/src/main/java/com/example/android/wearable/wear/wearnotifications/MainActivity.java
+++ b/wearable/wear/WearNotifications/Application/src/main/java/com/example/android/wearable/wear/wearnotifications/MainActivity.java
@@ -52,8 +52,7 @@
 
 /**
  * The Activity demonstrates several popular Notification.Style examples along with their best
- * practices (include proper Android Wear support when you don't have a dedicated Android Wear
- * app).
+ * practices (include proper Wear support when you don't have a dedicated Wear app).
  */
 public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
 
@@ -309,7 +308,7 @@
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
                 // SIDE NOTE: Auto-bundling is enabled for 4 or more notifications on API 24+ (N+)
-                // devices and all Android Wear devices. If you have more than one notification and
+                // devices and all Wear devices. If you have more than one notification and
                 // you prefer a different summary notification, set a group key and create a
                 // summary notification via
                 // .setGroupSummary(true)
@@ -342,7 +341,7 @@
      *
      * This example Notification is a social post. It allows updating the notification with
      * comments/responses via RemoteInput and the BigPictureSocialIntentService on 24+ (N+) and
-     * Android Wear devices.
+     * Wear devices.
      */
     private void generateBigPictureStyleNotification() {
 
@@ -479,7 +478,7 @@
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
                 // SIDE NOTE: Auto-bundling is enabled for 4 or more notifications on API 24+ (N+)
-                // devices and all Android Wear devices. If you have more than one notification and
+                // devices and all Wear devices. If you have more than one notification and
                 // you prefer a different summary notification, set a group key and create a
                 // summary notification via
                 // .setGroupSummary(true)
@@ -617,7 +616,7 @@
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
                 // SIDE NOTE: Auto-bundling is enabled for 4 or more notifications on API 24+ (N+)
-                // devices and all Android Wear devices. If you have more than one notification and
+                // devices and all Wear devices. If you have more than one notification and
                 // you prefer a different summary notification, set a group key and create a
                 // summary notification via
                 // .setGroupSummary(true)
@@ -797,7 +796,7 @@
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
                 // SIDE NOTE: Auto-bundling is enabled for 4 or more notifications on API 24+ (N+)
-                // devices and all Android Wear devices. If you have more than one notification and
+                // devices and all Wear devices. If you have more than one notification and
                 // you prefer a different summary notification, set a group key and create a
                 // summary notification via
                 // .setGroupSummary(true)
diff --git a/wearable/wear/WearNotifications/Shared/build.gradle b/wearable/wear/WearNotifications/Shared/build.gradle
index 0970e28..2eb303b 100644
--- a/wearable/wear/WearNotifications/Shared/build.gradle
+++ b/wearable/wear/WearNotifications/Shared/build.gradle
@@ -2,10 +2,11 @@
 buildscript {
     repositories {
         jcenter()
+        google()
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.1'
     }
 }
 
@@ -13,13 +14,11 @@
 
 repositories {
     jcenter()
-    maven {
-        url 'https://maven.google.com'
-    }
+    google()
 }
 
 dependencies {
-    compile 'com.android.support:support-v4:26.0.0'
+    compile 'com.android.support:support-v4:27.1.0'
 }
 
 // The sample build uses multiple directories to
@@ -31,13 +30,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 26
+    compileSdkVersion 27
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "27.0.3"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 26
+        targetSdkVersion 27
     }
 
     compileOptions {
diff --git a/wearable/wear/WearNotifications/Wearable/src/main/AndroidManifest.xml b/wearable/wear/WearNotifications/Wearable/src/main/AndroidManifest.xml
index 084bc35..392b7ed 100644
--- a/wearable/wear/WearNotifications/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/WearNotifications/Wearable/src/main/AndroidManifest.xml
@@ -34,7 +34,7 @@
 
         <!--
         Important Note: Usually, you will want to disable bridging if you have a local/native
-        Android Wear app creating Notifications. In our case, we don't, as our sample shows both
+        Wear app creating Notifications. In our case, we don't, as our sample shows both
         Notifications launched from a Phone app (that needed to be bridged) and a Wear app.
 
         To disable, create a meta-data tag here:
diff --git a/wearable/wear/WearNotifications/Wearable/src/main/java/com/example/android/wearable/wear/wearnotifications/StandaloneMainActivity.java b/wearable/wear/WearNotifications/Wearable/src/main/java/com/example/android/wearable/wear/wearnotifications/StandaloneMainActivity.java
index eb8842c..5ba3b97 100644
--- a/wearable/wear/WearNotifications/Wearable/src/main/java/com/example/android/wearable/wear/wearnotifications/StandaloneMainActivity.java
+++ b/wearable/wear/WearNotifications/Wearable/src/main/java/com/example/android/wearable/wear/wearnotifications/StandaloneMainActivity.java
@@ -15,6 +15,7 @@
  */
 package com.example.android.wearable.wear.wearnotifications;
 
+import android.app.Activity;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Intent;
@@ -30,9 +31,9 @@
 import android.support.v4.app.NotificationManagerCompat;
 import android.support.v4.app.RemoteInput;
 import android.support.v4.content.ContextCompat;
+import android.support.wear.ambient.AmbientMode;
 import android.support.wear.widget.WearableLinearLayoutManager;
 import android.support.wear.widget.WearableRecyclerView;
-import android.support.wearable.activity.WearableActivity;
 import android.util.Log;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -50,10 +51,11 @@
 
 /**
  * Demonstrates best practice for {@link NotificationCompat} Notifications created by local
- * standalone Android Wear apps. All {@link NotificationCompat} examples use
+ * standalone Wear apps. All {@link NotificationCompat} examples use
  * {@link NotificationCompat.Style}.
  */
-public class StandaloneMainActivity extends WearableActivity {
+public class StandaloneMainActivity extends Activity implements
+        AmbientMode.AmbientCallbackProvider {
 
     private static final String TAG = "StandaloneMainActivity";
 
@@ -83,18 +85,26 @@
     private WearableRecyclerView mWearableRecyclerView;
     private CustomRecyclerAdapter mCustomRecyclerAdapter;
 
+    /**
+     * Ambient mode controller attached to this display. Used by Activity to see if it is in
+     * ambient mode.
+     */
+    private AmbientMode.AmbientController mAmbientController;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Log.d(TAG, "onCreate()");
 
         setContentView(R.layout.activity_main);
-        setAmbientEnabled();
+
+        // Enables Ambient mode.
+        mAmbientController = AmbientMode.attachAmbientSupport(this);
 
         mNotificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
 
-        mMainFrameLayout = (FrameLayout) findViewById(R.id.mainFrameLayout);
-        mWearableRecyclerView = (WearableRecyclerView) findViewById(R.id.recycler_view);
+        mMainFrameLayout = findViewById(R.id.mainFrameLayout);
+        mWearableRecyclerView = findViewById(R.id.recycler_view);
 
         // Aligns the first and last items on the list vertically centered on the screen.
         mWearableRecyclerView.setEdgeItemsCenteringEnabled(true);
@@ -339,7 +349,7 @@
      *
      * This example Notification is a social post. It allows updating the notification with
      * comments/responses via RemoteInput and the BigPictureSocialIntentService on 24+ (N+) and
-     * Android Wear devices.
+     * Wear devices.
      *
      * IMPORTANT NOTE:
      * Notification Styles behave slightly different on Wear 2.0 when they are launched by a
@@ -762,4 +772,30 @@
         intent.putExtra("app_uid", getApplicationInfo().uid);
         startActivity(intent);
     }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {
+        /** Prepares the UI for ambient mode. */
+        @Override
+        public void onEnterAmbient(Bundle ambientDetails) {
+            super.onEnterAmbient(ambientDetails);
+
+            Log.d(TAG, "onEnterAmbient() " + ambientDetails);
+            // In our case, the assets are already in black and white, so we don't update UI.
+        }
+
+        /** Restores the UI to active (non-ambient) mode. */
+        @Override
+        public void onExitAmbient() {
+            super.onExitAmbient();
+
+            Log.d(TAG, "onExitAmbient()");
+            // In our case, the assets are already in black and white, so we don't update UI.
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/wearable/wear/WearNotifications/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WearNotifications/gradle/wrapper/gradle-wrapper.properties
index 9fca6ff..eee1f3d 100644
--- a/wearable/wear/WearNotifications/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/WearNotifications/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/WearNotifications/template-params.xml b/wearable/wear/WearNotifications/template-params.xml
index 699b760..4268dcc 100644
--- a/wearable/wear/WearNotifications/template-params.xml
+++ b/wearable/wear/WearNotifications/template-params.xml
@@ -20,8 +20,8 @@
     <package>com.example.android.wearable.wear.wearnotifications</package>
 
     <minSdk>18</minSdk>
-    <compileSdkVersion>26</compileSdkVersion>
-    <targetSdkVersion>26</targetSdkVersion>
+    <compileSdkVersion>27</compileSdkVersion>
+    <targetSdkVersion>27</targetSdkVersion>
 
     <minSdkVersionWear>23</minSdkVersionWear>
     <compileSdkVersionWear>26</compileSdkVersionWear>
@@ -32,15 +32,15 @@
         <has_handheld_app>true</has_handheld_app>
     </wearable>
 
-    <dependency>com.android.support:appcompat-v7:26.0.0</dependency>
-    <dependency>com.android.support:cardview-v7:26.0.0</dependency>
-    <dependency>com.android.support:design:26.0.0</dependency>
+    <dependency>com.android.support:appcompat-v7:27.1.0</dependency>
+    <dependency>com.android.support:cardview-v7:27.1.0</dependency>
+    <dependency>com.android.support:design:27.1.0</dependency>
 
-    <dependency_shared>com.android.support:support-v4:26.0.0</dependency_shared>
+    <dependency_shared>com.android.support:support-v4:27.1.0</dependency_shared>
 
-    <dependency_wearable>com.android.support:appcompat-v7:26.0.0</dependency_wearable>
-    <dependency_wearable>com.android.support:wear:26.0.0</dependency_wearable>
-    <dependency_wearable>com.android.support:design:26.0.0</dependency_wearable>
+    <dependency_wearable>com.android.support:appcompat-v7:27.1.0</dependency_wearable>
+    <dependency_wearable>com.android.support:wear:27.1.0</dependency_wearable>
+    <dependency_wearable>com.android.support:design:27.1.0</dependency_wearable>
 
     <!-- Include additional dependencies here.-->
     <!-- dependency>com.google.android.gms:play-services:5.0.+</dependency -->
@@ -49,8 +49,8 @@
         <intro>
             <![CDATA[
             Sample demonstrates best practices for Notification Styles that support Android
-            phone/tablets and Android Wear. The phone app demonstrates best practices if you do not
-            have a dedicated Android Wear app for Notifications. While the Android Wear app
+            phone/tablets and Wear. The phone app demonstrates best practices if you
+            do not have a dedicated Wear app for Notifications. While the Wear app
             demonstrates best practices for a standalone Wear Notification experience without
             the Notifications showing on the phone/tablet.
             ]]>
@@ -119,7 +119,7 @@
             accomplish, and how does it do it? -->
         <description>
             Sample demonstrates best practices for using NotificationStyle Notifications (Inbox,
-            BigPicture, BigText, and Messaging) for both Mobile apps and native/local Android Wear
+            BigPicture, BigText, and Messaging) for both Mobile apps and native/local Wear
             apps. It also covers Notifications on Wear 1.+ and Wear 2.0.
         </description>
 
@@ -137,11 +137,11 @@
 This sample demonstrate best practices for using [NotificationStyle][1]
 [Notifications][2] for two scenarios:
 
-1. Launching Notifications from a Mobile app WITHOUT a native Android Wear app.
+1. Launching Notifications from a Mobile app WITHOUT a native Wear app.
 Notifications appear both on mobile and Wear (bridged to appear like a local/native
 Wear app).
 
-2. Launching Notifications from a Native/Local Android Wear app. Notifications only
+2. Launching Notifications from a Native/Local Wear app. Notifications only
 appear on Wear device.
 
 The Mobile and Wear apps demonstrate [BigTextStyle][3], [BigPictureStyle][4],
diff --git a/wearable/wear/WearSpeakerSample/build.gradle b/wearable/wear/WearSpeakerSample/build.gradle
index 18a3904..6c111e7 100644
--- a/wearable/wear/WearSpeakerSample/build.gradle
+++ b/wearable/wear/WearSpeakerSample/build.gradle
@@ -19,9 +19,10 @@
 buildscript {
     repositories {
         jcenter()
+        google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.1'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
@@ -31,6 +32,7 @@
 allprojects {
     repositories {
         jcenter()
+        google()
     }
 }
 
diff --git a/wearable/wear/WearSpeakerSample/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WearSpeakerSample/gradle/wrapper/gradle-wrapper.properties
index 6abcb42..0b7e78b 100644
--- a/wearable/wear/WearSpeakerSample/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/WearSpeakerSample/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/WearSpeakerSample/wear/build.gradle b/wearable/wear/WearSpeakerSample/wear/build.gradle
index 5c2c234..19604a1 100644
--- a/wearable/wear/WearSpeakerSample/wear/build.gradle
+++ b/wearable/wear/WearSpeakerSample/wear/build.gradle
@@ -18,13 +18,13 @@
 
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.2"
+    compileSdkVersion 26
+    buildToolsVersion '26.0.2'
 
     defaultConfig {
         applicationId "com.example.android.wearable.speaker"
-        minSdkVersion 22
-        targetSdkVersion 25
+        minSdkVersion 23
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
     }
@@ -37,8 +37,12 @@
 }
 
 dependencies {
-    provided 'com.google.android.wearable:wearable:2.0.3'
-    compile 'com.google.android.support:wearable:2.0.3'
-    compile 'com.google.android.gms:play-services-wearable:10.2.6'
-    compile 'com.android.support:appcompat-v7:25.3.1'
+
+    compile 'com.android.support:wear:27.1.0'
+
+    compile 'com.google.android.gms:play-services-wearable:11.8.0'
+    compile 'com.android.support:appcompat-v7:27.1.0'
+
+    provided 'com.google.android.wearable:wearable:2.3.0'
+    compile 'com.google.android.support:wearable:2.3.0'
 }
diff --git a/wearable/wear/WearSpeakerSample/wear/src/main/java/com/example/android/wearable/speaker/MainActivity.java b/wearable/wear/WearSpeakerSample/wear/src/main/java/com/example/android/wearable/speaker/MainActivity.java
index e7a4870..e212195 100644
--- a/wearable/wear/WearSpeakerSample/wear/src/main/java/com/example/android/wearable/speaker/MainActivity.java
+++ b/wearable/wear/WearSpeakerSample/wear/src/main/java/com/example/android/wearable/speaker/MainActivity.java
@@ -17,8 +17,10 @@
 package com.example.android.wearable.speaker;
 
 import android.Manifest;
+import android.app.Activity;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.media.MediaPlayer;
@@ -27,11 +29,12 @@
 import android.os.CountDownTimer;
 import android.support.v4.app.ActivityCompat;
 import android.support.v4.content.ContextCompat;
-import android.support.wearable.activity.WearableActivity;
+import android.support.wear.ambient.AmbientMode;
 import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
 import android.widget.Toast;
 
 import java.util.concurrent.TimeUnit;
@@ -42,7 +45,9 @@
  * to 10 seconds), a Play icon (if clicked, it wil playback the recorded audio file) and a music
  * note icon (if clicked, it plays an MP3 file that is included in the app).
  */
-public class MainActivity extends WearableActivity implements UIAnimation.UIStateListener,
+public class MainActivity extends Activity implements
+        AmbientMode.AmbientCallbackProvider,
+        UIAnimation.UIStateListener,
         SoundRecorder.OnVoicePlaybackStateChangedListener {
 
     private static final String TAG = "MainActivity";
@@ -50,15 +55,25 @@
     private static final long COUNT_DOWN_MS = TimeUnit.SECONDS.toMillis(10);
     private static final long MILLIS_IN_SECOND = TimeUnit.SECONDS.toMillis(1);
     private static final String VOICE_FILE_NAME = "audiorecord.pcm";
+
     private MediaPlayer mMediaPlayer;
     private AppState mState = AppState.READY;
     private UIAnimation.UIState mUiState = UIAnimation.UIState.HOME;
     private SoundRecorder mSoundRecorder;
 
+    private RelativeLayout mOuterCircle;
+    private View mInnerCircle;
+
     private UIAnimation mUIAnimation;
     private ProgressBar mProgressBar;
     private CountDownTimer mCountDownTimer;
 
+    /**
+     * Ambient mode controller attached to this display. Used by Activity to see if it is in
+     * ambient mode.
+     */
+    private AmbientMode.AmbientController mAmbientController;
+
     enum AppState {
         READY, PLAYING_VOICE, PLAYING_MUSIC, RECORDING
     }
@@ -67,9 +82,14 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main_activity);
-        mProgressBar = (ProgressBar) findViewById(R.id.progress);
-        mProgressBar.setMax((int) (COUNT_DOWN_MS / MILLIS_IN_SECOND));
-        setAmbientEnabled();
+
+        mOuterCircle = findViewById(R.id.outer_circle);
+        mInnerCircle = findViewById(R.id.inner_circle);
+
+        mProgressBar = findViewById(R.id.progress_bar);
+
+        // Enables Ambient mode.
+        mAmbientController = AmbientMode.attachAmbientSupport(this);
     }
 
     private void setProgressBar(long progressInMillis) {
@@ -234,7 +254,7 @@
         if (speakerIsSupported()) {
             checkPermissions();
         } else {
-            findViewById(R.id.container2).setOnClickListener(new View.OnClickListener() {
+            mOuterCircle.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
                     Toast.makeText(MainActivity.this, R.string.no_speaker_supported,
@@ -290,4 +310,56 @@
         }
         return false;
     }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {
+        /** Prepares the UI for ambient mode. */
+        @Override
+        public void onEnterAmbient(Bundle ambientDetails) {
+            super.onEnterAmbient(ambientDetails);
+
+            Log.d(TAG, "onEnterAmbient() " + ambientDetails);
+
+            // Changes views to grey scale.
+            Context context = getApplicationContext();
+            Resources resources = context.getResources();
+
+            mOuterCircle.setBackgroundColor(
+                    ContextCompat.getColor(context, R.color.light_grey));
+            mInnerCircle.setBackground(
+                    ContextCompat.getDrawable(context, R.drawable.grey_circle));
+
+            mProgressBar.setProgressTintList(
+                    resources.getColorStateList(R.color.white, context.getTheme()));
+            mProgressBar.setProgressBackgroundTintList(
+                    resources.getColorStateList(R.color.black, context.getTheme()));
+        }
+
+        /** Restores the UI to active (non-ambient) mode. */
+        @Override
+        public void onExitAmbient() {
+            super.onExitAmbient();
+
+            Log.d(TAG, "onExitAmbient()");
+
+            // Changes views to color.
+            Context context = getApplicationContext();
+            Resources resources = context.getResources();
+
+            mOuterCircle.setBackgroundColor(
+                    ContextCompat.getColor(context, R.color.background_color));
+            mInnerCircle.setBackground(
+                    ContextCompat.getDrawable(context, R.drawable.color_circle));
+
+            mProgressBar.setProgressTintList(
+                    resources.getColorStateList(R.color.progressbar_tint, context.getTheme()));
+            mProgressBar.setProgressBackgroundTintList(
+                    resources.getColorStateList(
+                            R.color.progressbar_background_tint, context.getTheme()));
+        }
+    }
 }
diff --git a/wearable/wear/WearSpeakerSample/wear/src/main/res/drawable/circle.xml b/wearable/wear/WearSpeakerSample/wear/src/main/res/drawable/color_circle.xml
similarity index 100%
rename from wearable/wear/WearSpeakerSample/wear/src/main/res/drawable/circle.xml
rename to wearable/wear/WearSpeakerSample/wear/src/main/res/drawable/color_circle.xml
diff --git a/wearable/wear/WearSpeakerSample/wear/src/main/res/drawable/grey_circle.xml b/wearable/wear/WearSpeakerSample/wear/src/main/res/drawable/grey_circle.xml
new file mode 100644
index 0000000..deac09a
--- /dev/null
+++ b/wearable/wear/WearSpeakerSample/wear/src/main/res/drawable/grey_circle.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2015 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.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
+    <size android:width="100dp"
+        android:height="100dp"/>
+    <stroke
+        android:width="3dp"
+        android:color="@color/grey"/>
+    <solid android:color="@color/grey"/>
+</shape>
\ No newline at end of file
diff --git a/wearable/wear/WearSpeakerSample/wear/src/main/res/layout/main_activity.xml b/wearable/wear/WearSpeakerSample/wear/src/main/res/layout/main_activity.xml
index 7e004ad..42a73b6 100644
--- a/wearable/wear/WearSpeakerSample/wear/src/main/res/layout/main_activity.xml
+++ b/wearable/wear/WearSpeakerSample/wear/src/main/res/layout/main_activity.xml
@@ -18,17 +18,17 @@
 
 
     <RelativeLayout
-        android:id="@+id/container2"
+        android:id="@+id/outer_circle"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:background="@color/background_color">
 
         <View
-            android:id="@+id/circle"
+            android:id="@+id/inner_circle"
             android:layout_width="140dp"
             android:layout_height="140dp"
             android:layout_centerInParent="true"
-            android:background="@drawable/circle" />
+            android:background="@drawable/color_circle" />
 
         <View
             android:id="@+id/center"
@@ -67,13 +67,13 @@
             android:src="@drawable/ic_audiotrack_32dp" />
 
         <ProgressBar
-            android:id="@+id/progress"
+            android:id="@+id/progress_bar"
             style="?android:attr/progressBarStyleHorizontal"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_alignStart="@+id/circle"
-            android:layout_alignEnd="@+id/circle"
-            android:layout_below="@+id/circle"
+            android:layout_alignStart="@+id/inner_circle"
+            android:layout_alignEnd="@+id/inner_circle"
+            android:layout_below="@+id/inner_circle"
             android:progressTint="@color/progressbar_tint"
             android:progressBackgroundTint="@color/progressbar_background_tint"
             android:layout_marginTop="5dp"
diff --git a/wearable/wear/WearVerifyRemoteApp/Wearable/build.gradle b/wearable/wear/WearVerifyRemoteApp/Wearable/build.gradle
index fc4aaa4..bb93be9 100644
--- a/wearable/wear/WearVerifyRemoteApp/Wearable/build.gradle
+++ b/wearable/wear/WearVerifyRemoteApp/Wearable/build.gradle
@@ -2,10 +2,11 @@
 buildscript {
     repositories {
         jcenter()
+        google()
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.1'
     }
 }
 
@@ -13,23 +14,22 @@
 
 repositories {
     jcenter()
-    maven {
-        url 'https://maven.google.com'
-    }
+    google()
 }
 
 
 
 dependencies {
 
+    compile 'com.android.support:wear:27.1.0'
 
 
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile 'com.google.android.gms:play-services-wearable:11.8.0'
+    compile 'com.android.support:support-v13:27.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.3.0'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.3.0'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+    compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "27.0.3"
 
     defaultConfig {
         versionCode 1
@@ -53,7 +53,7 @@
 
         minSdkVersion 23
 
-        targetSdkVersion 25
+        targetSdkVersion 26
 
 
     }
diff --git a/wearable/wear/WearVerifyRemoteApp/Wearable/src/main/java/com/example/android/wearable/wear/wearverifyremoteapp/MainWearActivity.java b/wearable/wear/WearVerifyRemoteApp/Wearable/src/main/java/com/example/android/wearable/wear/wearverifyremoteapp/MainWearActivity.java
index 31882b0..53b71aa 100644
--- a/wearable/wear/WearVerifyRemoteApp/Wearable/src/main/java/com/example/android/wearable/wear/wearverifyremoteapp/MainWearActivity.java
+++ b/wearable/wear/WearVerifyRemoteApp/Wearable/src/main/java/com/example/android/wearable/wear/wearverifyremoteapp/MainWearActivity.java
@@ -15,6 +15,7 @@
  */
 package com.example.android.wearable.wear.wearverifyremoteapp;
 
+import android.app.Activity;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
@@ -22,7 +23,8 @@
 import android.os.ResultReceiver;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.wearable.activity.WearableActivity;
+import android.support.wear.ambient.AmbientMode;
+import android.support.wearable.phone.PhoneDeviceType;
 import android.support.wearable.view.ConfirmationOverlay;
 import android.util.Log;
 import android.view.View;
@@ -38,7 +40,6 @@
 import com.google.android.gms.wearable.Node;
 import com.google.android.gms.wearable.Wearable;
 import com.google.android.wearable.intent.RemoteIntent;
-import com.google.android.wearable.playstore.PlayStoreAvailability;
 
 import java.util.Set;
 
@@ -46,7 +47,8 @@
  * Checks if the phone app is installed on remote device. If it is not, allows user to open app
  * listing on the phone's Play or App Store.
  */
-public class MainWearActivity extends WearableActivity implements
+public class MainWearActivity extends Activity implements
+        AmbientMode.AmbientCallbackProvider,
         GoogleApiClient.ConnectionCallbacks,
         GoogleApiClient.OnConnectionFailedListener,
         CapabilityApi.CapabilityListener {
@@ -74,7 +76,7 @@
 
     // Links to install mobile app for both Android (Play Store) and iOS.
     // TODO: Replace with your links/packages.
-    private static final String PLAY_STORE_APP_URI =
+    private static final String ANDROID_MARKET_APP_URI =
             "market://details?id=com.example.android.wearable.wear.wearverifyremoteapp";
 
     // TODO: Replace with your links/packages.
@@ -113,7 +115,9 @@
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.activity_main);
-        setAmbientEnabled();
+
+        // Enables Ambient mode.
+        AmbientMode.attachAmbientSupport(this);
 
         mInformationTextView = (TextView) findViewById(R.id.information_text_view);
         mRemoteOpenButton = (Button) findViewById(R.id.remote_open_button);
@@ -242,20 +246,16 @@
     private void openAppInStoreOnPhone() {
         Log.d(TAG, "openAppInStoreOnPhone()");
 
-        int playStoreAvailabilityOnPhone =
-                PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(getApplicationContext());
-
-        switch (playStoreAvailabilityOnPhone) {
-
-            // Android phone with the Play Store.
-            case PlayStoreAvailability.PLAY_STORE_ON_PHONE_AVAILABLE:
-                Log.d(TAG, "\tPLAY_STORE_ON_PHONE_AVAILABLE");
-
+        int phoneDeviceType = PhoneDeviceType.getPhoneDeviceType(getApplicationContext());
+        switch (phoneDeviceType) {
+            // Paired to Android phone, use Play Store URI.
+            case PhoneDeviceType.DEVICE_TYPE_ANDROID:
+                Log.d(TAG, "\tDEVICE_TYPE_ANDROID");
                 // Create Remote Intent to open Play Store listing of app on remote device.
                 Intent intentAndroid =
                         new Intent(Intent.ACTION_VIEW)
                                 .addCategory(Intent.CATEGORY_BROWSABLE)
-                                .setData(Uri.parse(PLAY_STORE_APP_URI));
+                                .setData(Uri.parse(ANDROID_MARKET_APP_URI));
 
                 RemoteIntent.startRemoteActivity(
                         getApplicationContext(),
@@ -263,9 +263,9 @@
                         mResultReceiver);
                 break;
 
-            // Assume iPhone (iOS device) or Android without Play Store (not supported right now).
-            case PlayStoreAvailability.PLAY_STORE_ON_PHONE_UNAVAILABLE:
-                Log.d(TAG, "\tPLAY_STORE_ON_PHONE_UNAVAILABLE");
+            // Paired to iPhone, use iTunes App Store URI
+            case PhoneDeviceType.DEVICE_TYPE_IOS:
+                Log.d(TAG, "\tDEVICE_TYPE_IOS");
 
                 // Create Remote Intent to open App Store listing of app on iPhone.
                 Intent intentIOS =
@@ -279,8 +279,8 @@
                         mResultReceiver);
                 break;
 
-            case PlayStoreAvailability.PLAY_STORE_ON_PHONE_ERROR_UNKNOWN:
-                Log.d(TAG, "\tPLAY_STORE_ON_PHONE_ERROR_UNKNOWN");
+            case PhoneDeviceType.DEVICE_TYPE_ERROR_UNKNOWN:
+                Log.d(TAG, "\tDEVICE_TYPE_ERROR_UNKNOWN");
                 break;
         }
     }
@@ -299,4 +299,29 @@
         }
         return bestNodeId;
     }
-}
\ No newline at end of file
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {
+        /** Prepares the UI for ambient mode. */
+        @Override
+        public void onEnterAmbient(Bundle ambientDetails) {
+            super.onEnterAmbient(ambientDetails);
+
+            Log.d(TAG, "onEnterAmbient() " + ambientDetails);
+            // In our case, the assets are already in black and white, so we don't update UI.
+        }
+
+        /** Restores the UI to active (non-ambient) mode. */
+        @Override
+        public void onExitAmbient() {
+            super.onExitAmbient();
+
+            Log.d(TAG, "onExitAmbient()");
+            // In our case, the assets are already in black and white, so we don't update UI.
+        }
+    }
+}
diff --git a/wearable/wear/WearVerifyRemoteApp/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WearVerifyRemoteApp/gradle/wrapper/gradle-wrapper.properties
index 4da4a58..ba9b119 100644
--- a/wearable/wear/WearVerifyRemoteApp/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/WearVerifyRemoteApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/wearable/wear/WearVerifyRemoteApp/template-params.xml b/wearable/wear/WearVerifyRemoteApp/template-params.xml
index f45d4cb..6c3f3f9 100644
--- a/wearable/wear/WearVerifyRemoteApp/template-params.xml
+++ b/wearable/wear/WearVerifyRemoteApp/template-params.xml
@@ -23,14 +23,18 @@
     <!-- change minSdk if needed-->
     <minSdk>23</minSdk>
     <minSdkVersionWear>23</minSdkVersionWear>
-    <targetSdkVersion>25</targetSdkVersion>
-    <targetSdkVersionWear>25</targetSdkVersionWear>
+    <targetSdkVersion>27</targetSdkVersion>
+    <compileSdkVersionWear>26</compileSdkVersionWear>
+    <targetSdkVersionWear>26</targetSdkVersionWear>
 
     <wearable>
         <has_handheld_app>true</has_handheld_app>
     </wearable>
 
-    <dependency>com.google.android.support:wearable:2.0.3</dependency>
+    <dependency>com.google.android.support:wearable:2.3.0</dependency>
+
+
+    <dependency_wearable>com.android.support:wear:27.1.0</dependency_wearable>
 
     <!-- Include additional dependencies here.-->
     <!-- dependency>com.google.android.gms:play-services:5.0.+</dependency -->
@@ -39,7 +43,7 @@
         <intro>
 <![CDATA[
 Sample demonstrates best practices for checking if the remote version of your app is installed on a
-connected device. This enables standalone Android Wear apps to check if the phone app is installed
+connected device. This enables standalone Wear apps to check if the phone app is installed
 and the other way around.
 ]]>
         </intro>
@@ -94,7 +98,7 @@
         <description>
 <![CDATA[
 Sample demonstrates best practices for checking if connected mobile device has your app installed
-from an Android Wear 2.+ standalone app and the other way around.
+from a Wear 2.+ standalone app and the other way around.
 ]]>
         </description>
 
diff --git a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/service/UtilityService.java b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/service/UtilityService.java
index 3122d56..07e36f7 100644
--- a/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/service/UtilityService.java
+++ b/wearable/wear/XYZTouristAttractions/Application/src/main/java/com/example/android/xyztouristattractions/service/UtilityService.java
@@ -26,6 +26,7 @@
 import android.location.Location;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationManagerCompat;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
 
@@ -368,7 +369,7 @@
                 .setSmallIcon(R.drawable.ic_stat_maps_pin_drop)
                 .setContentIntent(pendingIntent)
                 .setDeleteIntent(deletePendingIntent)
-                .setColor(getResources().getColor(R.color.colorPrimary, getTheme()))
+                .setColor(ContextCompat.getColor(this, R.color.colorPrimary))
                 .setCategory(Notification.CATEGORY_RECOMMENDATION)
                 .setAutoCancel(true);
 
diff --git a/wearable/wear/XYZTouristAttractions/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/XYZTouristAttractions/gradle/wrapper/gradle-wrapper.properties
index f0ee620..0d23dbc 100644
--- a/wearable/wear/XYZTouristAttractions/gradle/wrapper/gradle-wrapper.properties
+++ b/wearable/wear/XYZTouristAttractions/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
diff --git a/wearable/wear/XYZTouristAttractions/template-params.xml b/wearable/wear/XYZTouristAttractions/template-params.xml
index c759446..1c751b0 100644
--- a/wearable/wear/XYZTouristAttractions/template-params.xml
+++ b/wearable/wear/XYZTouristAttractions/template-params.xml
@@ -19,8 +19,11 @@
     <group>Wearable</group>
     <package>com.example.android.xyztouristattractions</package>
     <minSdk>18</minSdk>
-    <targetSdkVersion>25</targetSdkVersion>
-    <targetSdkVersionWear>25</targetSdkVersionWear>
+    <targetSdkVersion>26</targetSdkVersion>
+    <targetSdkVersionWear>26</targetSdkVersionWear>
+    <compileSdkVersionWear>26</compileSdkVersionWear>
+    <minSdkVersionWear>23</minSdkVersionWear>
+
 
     <wearable>
         <has_handheld_app>true</has_handheld_app>
@@ -28,16 +31,17 @@
 
     <dependency>com.google.android.gms:play-services-location</dependency>
 
-    <dependency>com.google.maps.android:android-maps-utils:0.3.4</dependency>
-    <dependency>com.github.bumptech.glide:glide:3.6.1</dependency>
-    <dependency>com.android.support:appcompat-v7:25.3.1</dependency>
-    <dependency>com.android.support:recyclerview-v7:25.3.1</dependency>
-    <dependency>com.android.support:design:25.3.1</dependency>
+    <dependency>com.google.maps.android:android-maps-utils:0.5</dependency>
+    <dependency>com.github.bumptech.glide:glide:3.7.0</dependency>
+    <dependency>com.android.support:appcompat-v7:27.1.0</dependency>
+    <dependency>com.android.support:recyclerview-v7:27.1.0</dependency>
+    <dependency>com.android.support:design:27.1.0</dependency>
+
     <dependency_wearable>com.google.android.gms:play-services-maps</dependency_wearable>
-    <dependency_shared>com.android.support:support-v13:25.3.1</dependency_shared>
+    <dependency_shared>com.android.support:support-v13:27.1.0</dependency_shared>
     <dependency_shared>com.google.android.gms:play-services-wearable</dependency_shared>
     <dependency_shared>com.google.android.gms:play-services-maps</dependency_shared>
-    <dependency_shared>com.google.maps.android:android-maps-utils:0.3.4</dependency_shared>
+    <dependency_shared>com.google.maps.android:android-maps-utils:0.5</dependency_shared>
 
 
 
@@ -149,7 +153,7 @@
 noticeable to users as they will only be notified once the data has been sent).
 
 This sample aims to demonstrate a number of different Android APIs and concepts
-relating to [Android Wear][1] and location using [Google Play Services][2]:
+relating to [Wear][1] and location using [Google Play Services][2]:
 * Trigger a mobile notification that uses [WearableExtender][3] to customize the
 display on the wearable
 * Transmit data from the mobile app to the wearable (including binary blobs