Merge "DO NOT MERGE: Merge Oreo MR1 into master"
diff --git a/prebuilts/gradle/ActionBarCompat-Basic/.google/packaging.yaml b/prebuilts/gradle/ActionBarCompat-Basic/.google/packaging.yaml
index 3c18d1b..29a9236 100644
--- a/prebuilts/gradle/ActionBarCompat-Basic/.google/packaging.yaml
+++ b/prebuilts/gradle/ActionBarCompat-Basic/.google/packaging.yaml
@@ -14,6 +14,6 @@
 icon:         screenshots/big-icon.png
 apiRefs:
     - android:android.app.ActionBar
-    - android:android.support.v7.app.ActionBarActivity
+    - android:android.support.v7.app.AppCompatActivity
     - android:android.support.v4.view.MenuItemCompat
 license: apache2
diff --git a/prebuilts/gradle/ActionBarCompat-Basic/Application/build.gradle b/prebuilts/gradle/ActionBarCompat-Basic/Application/build.gradle
index 12dcfb1..43f4041 100644
--- a/prebuilts/gradle/ActionBarCompat-Basic/Application/build.gradle
+++ b/prebuilts/gradle/ActionBarCompat-Basic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ActionBarCompat-Basic/Application/src/main/java/com/example/android/actionbarcompat/basic/MainActivity.java b/prebuilts/gradle/ActionBarCompat-Basic/Application/src/main/java/com/example/android/actionbarcompat/basic/MainActivity.java
index 8d3506f..f3b14dc 100644
--- a/prebuilts/gradle/ActionBarCompat-Basic/Application/src/main/java/com/example/android/actionbarcompat/basic/MainActivity.java
+++ b/prebuilts/gradle/ActionBarCompat-Basic/Application/src/main/java/com/example/android/actionbarcompat/basic/MainActivity.java
@@ -18,7 +18,7 @@
 
 import android.os.Bundle;
 import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
 import android.view.Menu;
 import android.view.MenuItem;
 
@@ -26,10 +26,10 @@
  * This sample shows you how to use ActionBarCompat to create a basic Activity which displays
  * action items. It covers inflating items from a menu resource, as well as adding an item in code.
  *
- * This Activity extends from {@link ActionBarActivity}, which provides all of the function
+ * This Activity extends from {@link AppCompatActivity}, which provides all of the function
  * necessary to display a compatible Action Bar on devices running Android v2.1+.
  */
-public class MainActivity extends ActionBarActivity {
+public class MainActivity extends AppCompatActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/prebuilts/gradle/ActionBarCompat-Basic/README.md b/prebuilts/gradle/ActionBarCompat-Basic/README.md
index dd87b25..e95b853 100644
--- a/prebuilts/gradle/ActionBarCompat-Basic/README.md
+++ b/prebuilts/gradle/ActionBarCompat-Basic/README.md
@@ -22,7 +22,7 @@
 
 Using an ActionBar with the support library requires the following steps:
 
-1. Create your activity by extending ActionBarActivity.
+1. Create your activity by extending AppCompatActivity.
 2. Use (or extend) one of the Theme.AppCompat themes for your activity.
 
 Once this is done, action items will be created for any options menu items that
@@ -35,8 +35,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/build.gradle b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/build.gradle
index 12dcfb1..43f4041 100644
--- a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/build.gradle
+++ b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/src/main/java/com/example/android/actionbarcompat/listpopupmenu/MainActivity.java b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/src/main/java/com/example/android/actionbarcompat/listpopupmenu/MainActivity.java
index 13a77f3..4594a0c 100644
--- a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/src/main/java/com/example/android/actionbarcompat/listpopupmenu/MainActivity.java
+++ b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/Application/src/main/java/com/example/android/actionbarcompat/listpopupmenu/MainActivity.java
@@ -17,7 +17,7 @@
 package com.example.android.actionbarcompat.listpopupmenu;
 
 import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
 
 /**
  * This sample shows you how to use {@link android.support.v7.widget.PopupMenu PopupMenu} from
@@ -25,10 +25,10 @@
  * <p>
  * The interesting part of this sample is in {@link PopupListFragment}.
  *
- * This Activity extends from {@link ActionBarActivity}, which provides all of the function
+ * This Activity extends from {@link AppCompatActivity}, which provides all of the function
  * necessary to display a compatible Action Bar on devices running Android v2.1+.
  */
-public class MainActivity extends ActionBarActivity {
+public class MainActivity extends AppCompatActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/README.md b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/README.md
index ab7dc2f..5699a0e 100644
--- a/prebuilts/gradle/ActionBarCompat-ListPopupMenu/README.md
+++ b/prebuilts/gradle/ActionBarCompat-ListPopupMenu/README.md
@@ -17,8 +17,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ActionBarCompat-Styled/.google/packaging.yaml b/prebuilts/gradle/ActionBarCompat-Styled/.google/packaging.yaml
index b5dcbb6..6386648 100644
--- a/prebuilts/gradle/ActionBarCompat-Styled/.google/packaging.yaml
+++ b/prebuilts/gradle/ActionBarCompat-Styled/.google/packaging.yaml
@@ -13,5 +13,5 @@
 level:        INTERMEDIATE
 icon:         screenshots/big_icon.png
 apiRefs:
-    - android:android.support.v7.app.ActionBarActivity
+    - android:android.support.v7.app.AppCompatActivity
 license: apache2
diff --git a/prebuilts/gradle/ActionBarCompat-Styled/Application/build.gradle b/prebuilts/gradle/ActionBarCompat-Styled/Application/build.gradle
index 12dcfb1..43f4041 100644
--- a/prebuilts/gradle/ActionBarCompat-Styled/Application/build.gradle
+++ b/prebuilts/gradle/ActionBarCompat-Styled/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ActionBarCompat-Styled/Application/src/main/java/com/example/android/actionbarcompat/styled/MainActivity.java b/prebuilts/gradle/ActionBarCompat-Styled/Application/src/main/java/com/example/android/actionbarcompat/styled/MainActivity.java
index 19fe3a1..04163ef 100644
--- a/prebuilts/gradle/ActionBarCompat-Styled/Application/src/main/java/com/example/android/actionbarcompat/styled/MainActivity.java
+++ b/prebuilts/gradle/ActionBarCompat-Styled/Application/src/main/java/com/example/android/actionbarcompat/styled/MainActivity.java
@@ -19,14 +19,14 @@
 import android.os.Bundle;
 import android.support.v4.app.FragmentTransaction;
 import android.support.v7.app.ActionBar;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
 import android.view.Menu;
 
 /**
  * This sample shows you how to use ActionBarCompat with a customized theme. It utilizes a split
  * action bar when running on a device with a narrow display, and show three tabs.
  *
- * This Activity extends from {@link ActionBarActivity}, which provides all of the function
+ * This Activity extends from {@link AppCompatActivity}, which provides all of the function
  * necessary to display a compatible Action Bar on devices running Android v2.1+.
  *
  * The interesting bits of this sample start in the theme files
@@ -35,7 +35,7 @@
  * Many of the drawables used in this sample were generated with the
  * 'Android Action Bar Style Generator': http://jgilfelt.github.io/android-actionbarstylegenerator
  */
-public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {
+public class MainActivity extends AppCompatActivity implements ActionBar.TabListener {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/prebuilts/gradle/ActionBarCompat-Styled/README.md b/prebuilts/gradle/ActionBarCompat-Styled/README.md
index 4cb16df..b4623ff 100644
--- a/prebuilts/gradle/ActionBarCompat-Styled/README.md
+++ b/prebuilts/gradle/ActionBarCompat-Styled/README.md
@@ -11,7 +11,7 @@
 This sample shows how to style an ActionBar using the [support library][1] on devices running
 Android v2.1+ using a custom theme.
 
-This Activity extends from ActionBarActivity, which provides all of the function
+This Activity extends from AppCompatActivity, which provides all of the function
 necessary to display a compatible Action Bar on devices running Android v2.1+.
 A custom application theme and styles are defined in XML.
 
@@ -23,8 +23,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ActiveNotifications/Application/build.gradle b/prebuilts/gradle/ActiveNotifications/Application/build.gradle
index be6a1a3..bf2889f 100644
--- a/prebuilts/gradle/ActiveNotifications/Application/build.gradle
+++ b/prebuilts/gradle/ActiveNotifications/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,8 +34,10 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 24
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 24
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 24
diff --git a/prebuilts/gradle/ActiveNotifications/README.md b/prebuilts/gradle/ActiveNotifications/README.md
index 6f20204..4278eae 100644
--- a/prebuilts/gradle/ActiveNotifications/README.md
+++ b/prebuilts/gradle/ActiveNotifications/README.md
@@ -32,7 +32,7 @@
 --------------
 
 - Android SDK 24
-- Android Build Tools v25.0.3
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ActivityInstrumentation/Application/build.gradle b/prebuilts/gradle/ActivityInstrumentation/Application/build.gradle
index 12dcfb1..43f4041 100644
--- a/prebuilts/gradle/ActivityInstrumentation/Application/build.gradle
+++ b/prebuilts/gradle/ActivityInstrumentation/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ActivityInstrumentation/README.md b/prebuilts/gradle/ActivityInstrumentation/README.md
index b35798d..9d8145d 100644
--- a/prebuilts/gradle/ActivityInstrumentation/README.md
+++ b/prebuilts/gradle/ActivityInstrumentation/README.md
@@ -8,8 +8,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/ActivitySceneTransitionBasic/Application/build.gradle b/prebuilts/gradle/ActivitySceneTransitionBasic/Application/build.gradle
index 90aaa70..5d3e926 100644
--- a/prebuilts/gradle/ActivitySceneTransitionBasic/Application/build.gradle
+++ b/prebuilts/gradle/ActivitySceneTransitionBasic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.squareup.picasso:picasso:2.4.0'
 }
 
@@ -32,12 +35,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ActivitySceneTransitionBasic/README.md b/prebuilts/gradle/ActivitySceneTransitionBasic/README.md
index 93fe2b9..1163fd2 100644
--- a/prebuilts/gradle/ActivitySceneTransitionBasic/README.md
+++ b/prebuilts/gradle/ActivitySceneTransitionBasic/README.md
@@ -19,8 +19,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AdvancedImmersiveMode/Application/build.gradle b/prebuilts/gradle/AdvancedImmersiveMode/Application/build.gradle
index 19aaade..1728dc8 100644
--- a/prebuilts/gradle/AdvancedImmersiveMode/Application/build.gradle
+++ b/prebuilts/gradle/AdvancedImmersiveMode/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 19
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/AdvancedImmersiveMode/README.md b/prebuilts/gradle/AdvancedImmersiveMode/README.md
index a03c8e6..714061a 100644
--- a/prebuilts/gradle/AdvancedImmersiveMode/README.md
+++ b/prebuilts/gradle/AdvancedImmersiveMode/README.md
@@ -26,8 +26,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AgendaData/Application/build.gradle b/prebuilts/gradle/AgendaData/Application/build.gradle
index ea34a82..46183d5 100644
--- a/prebuilts/gradle/AgendaData/Application/build.gradle
+++ b/prebuilts/gradle/AgendaData/Application/build.gradle
@@ -19,13 +19,13 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.android.support:design:24.0.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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     wearApp project(':Wearable')
 }
 
@@ -39,9 +39,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/AgendaData/README.md b/prebuilts/gradle/AgendaData/README.md
index c6c27e7..e837deb 100644
--- a/prebuilts/gradle/AgendaData/README.md
+++ b/prebuilts/gradle/AgendaData/README.md
@@ -22,8 +22,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AgendaData/Wearable/build.gradle b/prebuilts/gradle/AgendaData/Wearable/build.gradle
index fc4aaa4..deb0179 100644
--- a/prebuilts/gradle/AgendaData/Wearable/build.gradle
+++ b/prebuilts/gradle/AgendaData/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/AlwaysOn/README.md b/prebuilts/gradle/AlwaysOn/README.md
index e7d88f4..d6c76f1 100644
--- a/prebuilts/gradle/AlwaysOn/README.md
+++ b/prebuilts/gradle/AlwaysOn/README.md
@@ -24,8 +24,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AlwaysOn/Wearable/build.gradle b/prebuilts/gradle/AlwaysOn/Wearable/build.gradle
index 332123f..7f08251 100644
--- a/prebuilts/gradle/AlwaysOn/Wearable/build.gradle
+++ b/prebuilts/gradle/AlwaysOn/Wearable/build.gradle
@@ -25,12 +25,12 @@
     compile 'com.android.support:wear:26.0.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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -46,7 +46,7 @@
 
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/AppRestrictionEnforcer/Application/build.gradle b/prebuilts/gradle/AppRestrictionEnforcer/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/AppRestrictionEnforcer/Application/build.gradle
+++ b/prebuilts/gradle/AppRestrictionEnforcer/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/AppRestrictionEnforcer/README.md b/prebuilts/gradle/AppRestrictionEnforcer/README.md
index c92a389..b80dbb1 100644
--- a/prebuilts/gradle/AppRestrictionEnforcer/README.md
+++ b/prebuilts/gradle/AppRestrictionEnforcer/README.md
@@ -27,8 +27,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AppRestrictionSchema/Application/build.gradle b/prebuilts/gradle/AppRestrictionSchema/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/AppRestrictionSchema/Application/build.gradle
+++ b/prebuilts/gradle/AppRestrictionSchema/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/AppRestrictionSchema/README.md b/prebuilts/gradle/AppRestrictionSchema/README.md
index 3f20773..f3d56ff 100644
--- a/prebuilts/gradle/AppRestrictionSchema/README.md
+++ b/prebuilts/gradle/AppRestrictionSchema/README.md
@@ -54,8 +54,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AppRestrictions/Application/build.gradle b/prebuilts/gradle/AppRestrictions/Application/build.gradle
index 60de968..43e4f90 100644
--- a/prebuilts/gradle/AppRestrictions/Application/build.gradle
+++ b/prebuilts/gradle/AppRestrictions/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/AppRestrictions/README.md b/prebuilts/gradle/AppRestrictions/README.md
index ff6fe28..c28d9a9 100644
--- a/prebuilts/gradle/AppRestrictions/README.md
+++ b/prebuilts/gradle/AppRestrictions/README.md
@@ -27,8 +27,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AppShortcuts/README.md b/prebuilts/gradle/AppShortcuts/README.md
index 61ec0d6..7a6a5bc 100644
--- a/prebuilts/gradle/AppShortcuts/README.md
+++ b/prebuilts/gradle/AppShortcuts/README.md
@@ -39,8 +39,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AppUsageStatistics/Application/build.gradle b/prebuilts/gradle/AppUsageStatistics/Application/build.gradle
index e40e49d..2903e5e 100644
--- a/prebuilts/gradle/AppUsageStatistics/Application/build.gradle
+++ b/prebuilts/gradle/AppUsageStatistics/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.android.support:recyclerview-v7:+'
     compile 'com.android.support:appcompat-v7:21.+'
 }
@@ -33,12 +36,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsActivity.java b/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsActivity.java
index 4def465..0f73398 100644
--- a/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsActivity.java
+++ b/prebuilts/gradle/AppUsageStatistics/Application/src/main/java/com/example/android/appusagestatistics/AppUsageStatisticsActivity.java
@@ -17,12 +17,12 @@
 package com.example.android.appusagestatistics;
 
 import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
 
 /**
  * Launcher Activity for the App Usage Statistics sample app.
  */
-public class AppUsageStatisticsActivity extends ActionBarActivity {
+public class AppUsageStatisticsActivity extends AppCompatActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -34,4 +34,4 @@
                     .commit();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/prebuilts/gradle/AppUsageStatistics/README.md b/prebuilts/gradle/AppUsageStatistics/README.md
index db46779..19ef935 100644
--- a/prebuilts/gradle/AppUsageStatistics/README.md
+++ b/prebuilts/gradle/AppUsageStatistics/README.md
@@ -49,8 +49,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AsymmetricFingerprintDialog/Application/build.gradle b/prebuilts/gradle/AsymmetricFingerprintDialog/Application/build.gradle
index 84996ed..8e2e1d5 100644
--- a/prebuilts/gradle/AsymmetricFingerprintDialog/Application/build.gradle
+++ b/prebuilts/gradle/AsymmetricFingerprintDialog/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.squareup.dagger:dagger:1.2.2'
     compile 'com.squareup.dagger:dagger-compiler:1.2.2'
     compile 'junit:junit:4.12'
@@ -35,12 +38,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 23
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/AsymmetricFingerprintDialog/README.md b/prebuilts/gradle/AsymmetricFingerprintDialog/README.md
index ce9e94d..77c53cd 100644
--- a/prebuilts/gradle/AsymmetricFingerprintDialog/README.md
+++ b/prebuilts/gradle/AsymmetricFingerprintDialog/README.md
@@ -38,8 +38,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AutoBackupForApps/Application/build.gradle b/prebuilts/gradle/AutoBackupForApps/Application/build.gradle
index cdcf106..2ad233b 100644
--- a/prebuilts/gradle/AutoBackupForApps/Application/build.gradle
+++ b/prebuilts/gradle/AutoBackupForApps/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 23
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/AutoBackupForApps/README.md b/prebuilts/gradle/AutoBackupForApps/README.md
index 6a11b3d..6203aa7 100644
--- a/prebuilts/gradle/AutoBackupForApps/README.md
+++ b/prebuilts/gradle/AutoBackupForApps/README.md
@@ -26,8 +26,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/AutofillFramework/Application/build.gradle b/prebuilts/gradle/AutofillFramework/Application/build.gradle
index 35233ec..1dc66eb 100644
--- a/prebuilts/gradle/AutofillFramework/Application/build.gradle
+++ b/prebuilts/gradle/AutofillFramework/Application/build.gradle
@@ -1,47 +1,37 @@
-
-buildscript {
-    repositories {
-        jcenter()
-    }
-
-    dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
-    }
-}
-
 apply plugin: 'com.android.application'
 
-repositories {
-    jcenter()
-}
-
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    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.
-    'common',   // components that are reused by multiple samples
-    'template'] // boilerplate code that is generated by the sample template process
+    'main']     // main sample code; look here for the interesting stuff.
 
 android {
-    compileSdkVersion "android-O"
-    buildToolsVersion "25.0.3"
+    compileSdkVersion 26
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
-        minSdkVersion "O"
-        targetSdkVersion "O"
+        minSdkVersion 26
+        targetSdkVersion 26
+        jackOptions {
+            enabled true
+        }
     }
 
     compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
     }
 
     sourceSets {
@@ -53,7 +43,5 @@
         }
         androidTest.setRoot('tests')
         androidTest.java.srcDirs = ['tests/src']
-
     }
-
 }
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/AndroidManifest.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/AndroidManifest.xml
index 28d9c0b..0af5716 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/AndroidManifest.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
+<?xml version="1.0" encoding="UTF-8"?><!--
  Copyright 2017 The Android Open Source Project
 
  Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,11 +13,12 @@
  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.autofillframework"
-          android:versionCode="1"
-          android:versionName="1.0">
+    package="com.example.android.autofillframework"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.INTERNET"/>
 
     <application
         android:allowBackup="true"
@@ -28,7 +28,6 @@
         android:theme="@style/Theme.AppCompat.Light">
         <activity
             android:name=".app.MainActivity"
-            android:label="AF Main"
             android:taskAffinity=".MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -37,42 +36,46 @@
             </intent-filter>
         </activity>
         <activity
-            android:name=".app.LoginActivity"
-            android:label="AF StandardLogin"
-            android:taskAffinity=".LoginActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
+            android:name=".app.StandardSignInActivity"
+            android:taskAffinity=".StandardSignInActivity" />
         <activity
-            android:name=".app.VirtualLoginActivity"
-            android:label="AF VirtualLogin"
-            android:taskAffinity=".VirtualLoginActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </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:label="AF CreditCard"
-            android:taskAffinity=".CreditCardActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
+            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: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=".service.settings.SettingsActivity"
+            android:name=".multidatasetservice.settings.SettingsActivity"
             android:exported="true"
             android:label="@string/settings_name"
             android:taskAffinity=".SettingsActivity">
@@ -89,19 +92,19 @@
         Settings Activity based on what the meta-data resource points to.
         -->
         <service
-            android:name=".service.MyAutofillService"
-            android:permission="android.permission.BIND_AUTOFILL"
-            android:label="Sample Autofill Service">
+            android:name=".multidatasetservice.MyAutofillService"
+            android:label="Multi-Dataset Autofill Service"
+            android:permission="android.permission.BIND_AUTOFILL">
             <meta-data
                 android:name="android.autofill"
-                android:resource="@xml/autofill_service" />
+                android:resource="@xml/multidataset_service" />
 
             <intent-filter>
                 <action android:name="android.service.autofill.AutofillService" />
             </intent-filter>
         </service>
 
-        <activity android:name=".service.AuthActivity" />
+        <activity android:name=".multidatasetservice.AuthActivity" />
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java
index 5404990..b7de476 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java
@@ -15,7 +15,14 @@
  */
 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;
@@ -23,7 +30,8 @@
 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";
 
@@ -51,4 +59,96 @@
         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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.java
index a82de4c..83e8614 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.java
@@ -18,21 +18,21 @@
 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.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.Spinner;
+import android.view.autofill.AutofillManager;
+import android.widget.EditText;
 
 import com.example.android.autofillframework.R;
 
 public class CreditCardActivity extends AppCompatActivity {
 
-    private Spinner mCcExpirationDaySpinner;
-    private Spinner mCcExpirationMonthSpinner;
-    private Spinner mCcExpirationYearSpinner;
-    private Button mSubmitButton;
-    private Button mClearButton;
+    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);
@@ -40,51 +40,35 @@
     }
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
         setContentView(R.layout.credit_card_activity);
-
-        mSubmitButton = (Button) findViewById(R.id.submit);
-        mClearButton = (Button) findViewById(R.id.clear);
-        mCcExpirationDaySpinner = (Spinner) findViewById(R.id.expirationDay);
-        mCcExpirationMonthSpinner = (Spinner) findViewById(R.id.expirationMonth);
-        mCcExpirationYearSpinner = (Spinner) findViewById(R.id.expirationYear);
-
-        // 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);
-
-        ArrayAdapter<CharSequence> monthAdapter = ArrayAdapter.createFromResource
-                (this, R.array.month_array, android.R.layout.simple_spinner_item);
-        monthAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        mCcExpirationMonthSpinner.setAdapter(monthAdapter);
-
-        ArrayAdapter<CharSequence> yearAdapter = ArrayAdapter.createFromResource
-                (this, R.array.year_array, android.R.layout.simple_spinner_item);
-        yearAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        mCcExpirationYearSpinner.setAdapter(yearAdapter);
-
-        mSubmitButton.setOnClickListener(new View.OnClickListener() {
+        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();
             }
         });
-        mClearButton.setOnClickListener(new View.OnClickListener() {
+        findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
+                getSystemService(AutofillManager.class).cancel();
                 resetFields();
             }
         });
     }
 
     private void resetFields() {
-        //TODO
+        mCcExpDayView.setText("");
+        mCcExpMonthView.setText("");
+        mCcExpYearView.setText("");
+        mCcNumber.setText("");
+        mCcSecurityCode.setText("");
     }
 
     /**
@@ -92,7 +76,7 @@
      * any new data.
      */
     private void submit() {
-        Intent intent = WelcomeActivity.getStartActivityIntent(CreditCardActivity.this);
+        Intent intent = WelcomeActivity.getStartActivityIntent(this);
         startActivity(intent);
         finish();
     }
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardAntiPatternActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardAntiPatternActivity.java
new file mode 100644
index 0000000..a7c1429
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardAntiPatternActivity.java
@@ -0,0 +1,77 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardCompoundViewActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardCompoundViewActivity.java
new file mode 100644
index 0000000..05f57d0
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardCompoundViewActivity.java
@@ -0,0 +1,77 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardDatePickerActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardDatePickerActivity.java
new file mode 100644
index 0000000..940f5e4
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDateCompoundView.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDateCompoundView.java
new file mode 100644
index 0000000..afa105e
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDatePickerView.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDatePickerView.java
new file mode 100644
index 0000000..e8385fb
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDatePickerView.java
@@ -0,0 +1,164 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardSpinnersActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardSpinnersActivity.java
new file mode 100644
index 0000000..af1bed5
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CreditCardSpinnersActivity.java
@@ -0,0 +1,124 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.java
index 085f827..f6fb3a5 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.java
@@ -16,11 +16,16 @@
 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;
@@ -31,110 +36,180 @@
 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;
 
-
 /**
- * Custom View with virtual child views for Username/Password text fields.
+ * 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 int nextId;
-
-    private final ArrayList<Line> mLines = new ArrayList<>();
-    private final SparseArray<Item> mItems = new SparseArray<>();
-    private final AutofillManager mAfm;
-
-    private Line mFocusedLine;
+    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 mTopMargin;
-    private int mLeftMargin;
-    private int mVerticalGap;
     private int mLineLength;
-    private int mFocusedColor;
-    private int mUnfocusedColor;
 
-    private Line mUsernameLine;
-    private Line mPasswordLine;
+    public CustomVirtualView(Context context) {
+        this(context, null);
+    }
 
     public CustomVirtualView(Context context, AttributeSet attrs) {
-        super(context, attrs);
+        this(context, attrs, 0);
+    }
 
-        mAfm = context.getSystemService(AutofillManager.class);
+    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();
+    }
 
-        mUnfocusedColor = Color.BLACK;
-        mFocusedColor = Color.RED;
+    protected void resetCoordinates() {
         mTextPaint.setStyle(Style.FILL);
-        mTopMargin = 100;
-        mLeftMargin = 100;
-        mTextHeight = 90;
-        mVerticalGap = 10;
-
-        mLineLength = mTextHeight + mVerticalGap;
         mTextPaint.setTextSize(mTextHeight);
-        mUsernameLine = addLine("usernameField", context.getString(R.string.username_label),
-                new String[] {View.AUTOFILL_HINT_USERNAME}, "         ", true);
-        mPasswordLine = addLine("passwordField", context.getString(R.string.password_label),
-                new String[] {View.AUTOFILL_HINT_PASSWORD}, "         ", false);
-
-        Log.d(TAG, "Text height: " + mTextHeight);
+        mTopMargin = getPaddingTop();
+        mLeftMargin = getPaddingStart();
+        mLineLength = mTextHeight + VERTICAL_GAP;
     }
 
     @Override
     public void autofill(SparseArray<AutofillValue> values) {
-        // User has just selected a Dataset from the list of Autofill suggestions and the Dataset's
-        // AutofillValue gets passed into this method.
-        Log.d(TAG, "autoFill(): " + 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++) {
-            final int id = values.keyAt(i);
-            final AutofillValue value = values.valueAt(i);
-            final Item item = mItems.get(id);
+            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);
-                return;
+                continue;
             }
+
             if (!item.editable) {
-                Log.w(TAG, "Item for id " + id + " is not editable: " + item);
-                return;
+                showError(context.getString(R.string.message_autofill_readonly, item.text));
+                continue;
             }
-            // Set the item's text to the text wrapped in the AutofillValue.
-            item.text = value.getTextValue();
+
+            // 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 to pack in AutoFillService requests.
+        // 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 = mItems.size();
-        Log.d(TAG, "onProvideAutofillVirtualStructure(): flags = " + flags + ", items = "
-                + childrenSize + ", extras: " + bundleToString(structure.getExtras()));
+        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 = mItems.valueAt(i);
-            Log.d(TAG, "Adding new child at index " + index + ": " + item);
+            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, item.id);
+            child.setAutofillId(structure.getAutofillId(), item.id);
             child.setAutofillHints(item.hints);
             child.setAutofillType(item.type);
+            child.setAutofillValue(item.getAutofillValue());
             child.setDataIsSensitive(!item.sanitized);
-            child.setText(item.text);
-            child.setAutofillValue(AutofillValue.forText(item.text));
             child.setFocused(item.focused);
-            child.setId(item.id, getContext().getPackageName(), null, item.line.idEntry);
+            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++;
         }
     }
@@ -143,24 +218,26 @@
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
-        Log.d(TAG, "onDraw: " + mLines.size() + " lines; canvas:" + canvas);
+        if (VERBOSE) {
+            Log.v(TAG, "onDraw(): " + mVirtualViewGroups.size() + " lines; canvas:" + canvas);
+        }
         float x;
         float y = mTopMargin + mLineLength;
-        for (int i = 0; i < mLines.size(); i++) {
+        for (int i = 0; i < mVirtualViewGroups.size(); i++) {
+            Line line = mVirtualViewGroups.get(i);
             x = mLeftMargin;
-            Line line = mLines.get(i);
-            Log.v(TAG, "Drawing '" + line + "' at " + x + "x" + y);
-            mTextPaint.setColor(line.fieldTextItem.focused ? mFocusedColor : mUnfocusedColor);
-            String readOnlyText = line.labelItem.text + ":  [";
-            String writeText = line.fieldTextItem.text + "]";
+            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.bounds.set((int) x, (int) (y - mLineLength),
+            line.mBounds.set((int) x, (int) (y - mLineLength),
                     (int) (x + mTextPaint.measureText(writeText)), (int) y);
-            Log.d(TAG, "setBounds(" + x + ", " + y + "): " + line.bounds);
+            if (VERBOSE) Log.v(TAG, "setBounds(" + x + ", " + y + "): " + line.mBounds);
             canvas.drawText(writeText, x, y, mTextPaint);
             y += mLineLength;
         }
@@ -169,13 +246,25 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         int y = (int) event.getY();
-        Log.d(TAG, "Touched: y=" + y + ", range=" + mLineLength + ", top=" + mTopMargin);
+        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 < mLines.size(); i++) {
+        for (int i = 0; i < mVirtualViewGroups.size(); i++) {
+            Line line = mVirtualViewGroups.get(i);
             upperY = lowerY + mLineLength;
-            Line line = mLines.get(i);
-            Log.d(TAG, "Line " + i + " ranges from " + lowerY + " to " + upperY);
+            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);
@@ -189,44 +278,57 @@
             }
             lowerY += mLineLength;
         }
-        return super.onTouchEvent(event);
     }
 
-    public CharSequence getUsernameText() {
-        return mUsernameLine.fieldTextItem.text;
+    /**
+     * 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;
     }
 
-    public CharSequence getPasswordText() {
-        return mPasswordLine.fieldTextItem.text;
+    private void showError(String message) {
+        showMessage(true, message);
     }
 
-    public void resetFields() {
-        mUsernameLine.reset();
-        mPasswordLine.reset();
-        postInvalidate();
+    private void showMessage(String message) {
+        showMessage(false, message);
     }
 
-    private Line addLine(String idEntry, String label, String[] hints, String text, boolean sanitized) {
-        Line line = new Line(idEntry, label, hints, text, sanitized);
-        mLines.add(line);
-        mItems.put(line.labelItem.id, line.labelItem);
-        mItems.put(line.fieldTextItem.id, line.fieldTextItem);
-        return line;
+    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();
     }
 
-    private static final class Item {
+
+    protected static final class Item {
+        protected final int id;
+        private final String idEntry;
         private final Line line;
-        private final int id;
         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[] hints, int type, CharSequence text, boolean editable, boolean sanitized) {
+        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;
@@ -236,61 +338,153 @@
 
         @Override
         public String toString() {
-            return id + ": " + text + (editable ? " (editable)" : " (read-only)"
-                    + (sanitized ? " (sanitized)" : " (sensitive"));
+            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;
+            }
+        }
     }
 
-    private final class Line {
+    /**
+     * 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<>();
 
-        // Boundaries of the text field, relative to the CustomView
-        final Rect bounds = new Rect();
-        private Item labelItem;
-        private Item fieldTextItem;
-        private String idEntry;
-
-        private Line(String idEntry, String label, String[] hints, String text, boolean sanitized) {
-            this.idEntry = idEntry;
-            this.labelItem = new Item(this, ++nextId, null, AUTOFILL_TYPE_NONE, label, false, true);
-            this.fieldTextItem = new Item(this, ++nextId, hints, AUTOFILL_TYPE_TEXT, text, true, sanitized);
+        private Partition(String name) {
+            mName = name;
         }
 
-        void changeFocus(boolean focused) {
-            fieldTextItem.focused = focused;
+        /**
+         * 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) {
-                final Rect absBounds = getAbsCoordinates();
-                Log.d(TAG, "focus gained on " + fieldTextItem.id + "; absBounds=" + absBounds);
-                mAfm.notifyViewEntered(CustomVirtualView.this, fieldTextItem.id, absBounds);
+                Rect absBounds = getAbsCoordinates();
+                if (DEBUG) {
+                    Log.d(TAG, "focus gained on " + mFieldTextItem.id + "; absBounds=" + absBounds);
+                }
+                mAutofillManager.notifyViewEntered(CustomVirtualView.this, mFieldTextItem.id,
+                        absBounds);
             } else {
-                Log.d(TAG, "focus lost on " + fieldTextItem.id);
-                mAfm.notifyViewExited(CustomVirtualView.this, fieldTextItem.id);
+                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.
-            final int offset[] = new int[2];
+            int offset[] = new int[2];
             getLocationOnScreen(offset);
-            final Rect absBounds = new Rect(bounds.left + offset[0],
-                    bounds.top + offset[1],
-                    bounds.right + offset[0], bounds.bottom + offset[1]);
-            Log.v(TAG, "getAbsCoordinates() for " + fieldTextItem.id + ": bounds=" + bounds
-                    + " offset: " + Arrays.toString(offset) + " absBounds: " + absBounds);
+            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() {
-            fieldTextItem.text = "        ";
+            mFieldTextItem.text = "        ";
         }
 
         @Override
         public String toString() {
-            return "Label: " + labelItem + " Text: " + fieldTextItem + " Focused: " +
-                    fieldTextItem.focused;
+            return "Label: " + mLabelItem + " Text: " + mFieldTextItem + " Focused: " +
+                    mFieldTextItem.focused + " Type: " + mAutofillType;
         }
     }
 }
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/EmailComposeActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/EmailComposeActivity.java
new file mode 100644
index 0000000..957d7aa
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/EmailComposeActivity.java
@@ -0,0 +1,46 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/InfoButton.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/InfoButton.java
new file mode 100644
index 0000000..d5811e1
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.java
index 4b27010..0e139f9 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.java
@@ -15,11 +15,11 @@
  */
 package com.example.android.autofillframework.app;
 
-import android.app.Activity;
 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;
@@ -29,42 +29,115 @@
  */
 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);
-        findViewById(R.id.standardViewSignInButton).setOnClickListener(new View.OnClickListener() {
+        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) {
-                standardViewSignIn();
+                startActivity(StandardSignInActivity.getStartActivityIntent(MainActivity.this));
             }
         });
-        findViewById(R.id.virtualViewSignInButton).setOnClickListener(new View.OnClickListener() {
+        loginCustomVirtual.setNavigationButtonClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
-                virtualViewSignIn();
+                startActivity(VirtualSignInActivity.getStartActivityIntent(MainActivity.this));
             }
         });
-        findViewById(R.id.creditCardCheckoutButton).setOnClickListener(new View.OnClickListener() {
+        creditCard.setNavigationButtonClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
-                creditCardCheckout();
+                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 void creditCardCheckout() {
-        Intent intent = CreditCardActivity.getStartActivityIntent(this);
-        startActivity(intent);
-    }
-
-    private void standardViewSignIn() {
-        Intent intent = LoginActivity.getStartActivityIntent(this);
-        startActivity(intent);
-    }
-
-    private void virtualViewSignIn() {
-        Intent intent = VirtualLoginActivity.getStartActivityIntent(this);
-        startActivity(intent);
+    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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MultiplePartitionsActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MultiplePartitionsActivity.java
new file mode 100644
index 0000000..319ed19
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/MultiplePartitionsActivity.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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/NavigationItem.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/NavigationItem.java
new file mode 100644
index 0000000..baeef68
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/NavigationItem.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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/ScrollableCustomVirtualView.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/ScrollableCustomVirtualView.java
new file mode 100644
index 0000000..0ce5036
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardAutoCompleteSignInActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardAutoCompleteSignInActivity.java
new file mode 100644
index 0000000..5fbdd34
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardSignInActivity.java
similarity index 79%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.java
rename to prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardSignInActivity.java
index 3ec87da..9038e3d 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/StandardSignInActivity.java
@@ -20,21 +20,18 @@
 import android.os.Bundle;
 import android.support.v7.app.AppCompatActivity;
 import android.view.View;
-import android.widget.Button;
 import android.widget.EditText;
 import android.widget.Toast;
 
 import com.example.android.autofillframework.R;
 
-public class LoginActivity extends AppCompatActivity {
+public class StandardSignInActivity extends AppCompatActivity {
 
     private EditText mUsernameEditText;
     private EditText mPasswordEditText;
-    private Button mLoginButton;
-    private Button mClearButton;
 
     public static Intent getStartActivityIntent(Context context) {
-        Intent intent = new Intent(context, LoginActivity.class);
+        Intent intent = new Intent(context, StandardSignInActivity.class);
         return intent;
     }
 
@@ -43,18 +40,15 @@
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.login_activity);
-
-        mLoginButton = (Button) findViewById(R.id.login);
-        mClearButton = (Button) findViewById(R.id.clear);
-        mUsernameEditText = (EditText) findViewById(R.id.usernameField);
-        mPasswordEditText = (EditText) findViewById(R.id.passwordField);
-        mLoginButton.setOnClickListener(new View.OnClickListener() {
+        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();
             }
         });
-        mClearButton.setOnClickListener(new View.OnClickListener() {
+        findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 resetFields();
@@ -75,7 +69,7 @@
         String password = mPasswordEditText.getText().toString();
         boolean valid = isValidCredentials(username, password);
         if (valid) {
-            Intent intent = WelcomeActivity.getStartActivityIntent(LoginActivity.this);
+            Intent intent = WelcomeActivity.getStartActivityIntent(StandardSignInActivity.this);
             startActivity(intent);
             finish();
         } else {
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/VirtualSignInActivity.java
similarity index 64%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.java
rename to prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/VirtualSignInActivity.java
index 5a4a4f4..30e2539 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/VirtualSignInActivity.java
@@ -15,23 +15,28 @@
  */
 package com.example.android.autofillframework.app;
 
-import android.app.Activity;
 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;
 
-
-public class VirtualLoginActivity extends AppCompatActivity {
+/**
+ * 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, VirtualLoginActivity.class);
+        Intent intent = new Intent(context, VirtualSignInActivity.class);
         return intent;
     }
 
@@ -42,6 +47,16 @@
         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) {
@@ -52,24 +67,29 @@
             @Override
             public void onClick(View view) {
                 resetFields();
+                mAutofillManager.cancel();
             }
         });
+        mAutofillManager = getSystemService(AutofillManager.class);
     }
 
     private void resetFields() {
-        mCustomVirtualView.resetFields();
+        mUsernameLine.reset();
+        mPasswordLine.reset();
+        mCustomVirtualView.postInvalidate();
     }
 
     /**
      * Emulates a login action.
      */
     private void login() {
-        String username = mCustomVirtualView.getUsernameText().toString();
-        String password = mCustomVirtualView.getPasswordText().toString();
+        String username = mUsernameLine.getText().toString();
+        String password = mPasswordLine.getText().toString();
         boolean valid = isValidCredentials(username, password);
         if (valid) {
-            Intent intent = WelcomeActivity.getStartActivityIntent(VirtualLoginActivity.this);
+            Intent intent = WelcomeActivity.getStartActivityIntent(VirtualSignInActivity.this);
             startActivity(intent);
+            finish();
         } else {
             Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show();
         }
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WebViewSignInActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WebViewSignInActivity.java
new file mode 100644
index 0000000..5eb0b50
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WebViewSignInActivity.java
@@ -0,0 +1,61 @@
+/*
+* 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.java
index fd3df2f..13eb939 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.java
@@ -15,14 +15,18 @@
  */
 package com.example.android.autofillframework.app;
 
-import android.app.Activity;
 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;
 
-public class WelcomeActivity extends Activity {
+import static java.lang.Math.toIntExact;
+
+public class WelcomeActivity extends AppCompatActivity {
 
     public static Intent getStartActivityIntent(Context context) {
         return new Intent(context, WelcomeActivity.class);
@@ -32,5 +36,21 @@
     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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AuthActivity.java
similarity index 78%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java
rename to prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AuthActivity.java
index 768b2ee..631cc0a 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AuthActivity.java
@@ -13,9 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.example.android.autofillframework.service;
+package com.example.android.autofillframework.multidatasetservice;
 
-import android.app.Activity;
 import android.app.PendingIntent;
 import android.app.assist.AssistStructure;
 import android.content.Context;
@@ -25,19 +24,18 @@
 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.Button;
 import android.widget.EditText;
 import android.widget.Toast;
 
 import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.datasource.LocalAutofillRepository;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-import com.example.android.autofillframework.service.settings.MyPreferences;
+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;
 
@@ -52,14 +50,12 @@
  * 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 Activity {
+public class AuthActivity extends AppCompatActivity {
 
     // Unique id for dataset intents.
     private static int sDatasetPendingIntentId = 0;
 
     private EditText mMasterPassword;
-    private Button mCancel;
-    private Button mLogin;
     private Intent mReplyIntent;
 
     static IntentSender getAuthIntentSenderForResponse(Context context) {
@@ -79,20 +75,16 @@
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.auth_activity);
-        mCancel = findViewById(R.id.cancel);
-        mLogin = findViewById(R.id.login);
+        setContentView(R.layout.multidataset_service_auth_activity);
         mMasterPassword = findViewById(R.id.master_password);
-        mLogin.setOnClickListener(new OnClickListener() {
+        findViewById(R.id.login).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
                 login();
             }
 
         });
-
-        mCancel.setOnClickListener(new OnClickListener() {
+        findViewById(R.id.cancel).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
                 onFailure();
@@ -132,21 +124,21 @@
         Intent intent = getIntent();
         boolean forResponse = intent.getBooleanExtra(EXTRA_FOR_RESPONSE, true);
         AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE);
-        StructureParser parser = new StructureParser(structure);
-        parser.parse();
-        AutofillFieldsCollection autofillFields = parser.getAutofillFields();
-        int saveTypes = parser.getSaveTypes();
+        StructureParser parser = new StructureParser(getApplicationContext(), structure);
+        parser.parseForFill();
+        AutofillFieldMetadataCollection autofillFields = parser.getAutofillFields();
+        int saveTypes = autofillFields.getSaveType();
         mReplyIntent = new Intent();
-        HashMap<String, ClientFormData> clientFormDataMap =
-                LocalAutofillRepository.getInstance(this).getClientFormData
-                        (autofillFields.getFocusedHints(), autofillFields.getAllHints());
+        HashMap<String, FilledAutofillFieldCollection> clientFormDataMap =
+                SharedPrefsAutofillRepository.getInstance().getFilledAutofillFieldCollection
+                        (this, autofillFields.getFocusedHints(), autofillFields.getAllHints());
         if (forResponse) {
             setResponseIntent(AutofillHelper.newResponse
-                    (this, false, autofillFields, saveTypes, clientFormDataMap));
+                    (this, false, autofillFields, clientFormDataMap));
         } else {
             String datasetName = intent.getStringExtra(EXTRA_DATASET_NAME);
             setDatasetIntent(AutofillHelper.newDataset
-                    (this, autofillFields, clientFormDataMap.get(datasetName)));
+                    (this, autofillFields, clientFormDataMap.get(datasetName), false));
         }
     }
 
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.java
new file mode 100644
index 0000000..1e8427d
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadataCollection.java
similarity index 60%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java
rename to prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadataCollection.java
index 0354b98..59b8fcd 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadataCollection.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.example.android.autofillframework.service.model;
+package com.example.android.autofillframework.multidatasetservice;
 
 import android.view.autofill.AutofillId;
 
@@ -22,29 +22,33 @@
 import java.util.HashMap;
 import java.util.List;
 
-public final class AutofillFieldsCollection {
+/**
+ * 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<AutofillField>> mAutofillHintsToFieldsMap = new HashMap<>();
+    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 size = 0;
+    private int mSize = 0;
     private int mSaveType = 0;
 
-    public void add(AutofillField autofillField) {
-        mSaveType |= autofillField.getSaveType();
-        size++;
-        mAutofillIds.add(autofillField.getId());
-        List<String> hintsList = Arrays.asList(autofillField.getHints());
+    public void add(AutofillFieldMetadata autofillFieldMetadata) {
+        mSaveType |= autofillFieldMetadata.getSaveType();
+        mSize++;
+        mAutofillIds.add(autofillFieldMetadata.getId());
+        List<String> hintsList = Arrays.asList(autofillFieldMetadata.getHints());
         mAllAutofillHints.addAll(hintsList);
-        if (autofillField.isFocused()) {
+        if (autofillFieldMetadata.isFocused()) {
             mFocusedAutofillHints.addAll(hintsList);
         }
-        for (String hint : autofillField.getHints()) {
-            if (mAutofillHintsToFieldsMap.get(hint) == null) {
-                mAutofillHintsToFieldsMap.put(hint, new ArrayList<AutofillField>());
+        for (String hint : autofillFieldMetadata.getHints()) {
+            if (!mAutofillHintsToFieldsMap.containsKey(hint)) {
+                mAutofillHintsToFieldsMap.put(hint, new ArrayList<>());
             }
-            mAutofillHintsToFieldsMap.get(hint).add(autofillField);
+            mAutofillHintsToFieldsMap.get(hint).add(autofillFieldMetadata);
         }
     }
 
@@ -53,10 +57,10 @@
     }
 
     public AutofillId[] getAutofillIds() {
-        return mAutofillIds.toArray(new AutofillId[size]);
+        return mAutofillIds.toArray(new AutofillId[mSize]);
     }
 
-    public List<AutofillField> getFieldsForHint(String hint) {
+    public List<AutofillFieldMetadata> getFieldsForHint(String hint) {
         return mAutofillHintsToFieldsMap.get(hint);
     }
 
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java
new file mode 100644
index 0000000..4c0f173
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java
@@ -0,0 +1,117 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHintProperties.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHintProperties.java
new file mode 100644
index 0000000..5a79377
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHintProperties.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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHints.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHints.java
new file mode 100644
index 0000000..af42b10
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHints.java
@@ -0,0 +1,774 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/FakeFieldGenerator.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/FakeFieldGenerator.java
new file mode 100644
index 0000000..383de21
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/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.autofillframework.multidatasetservice;
+
+import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField;
+
+interface FakeFieldGenerator {
+    FilledAutofillField generate(int seed);
+}
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.java
new file mode 100644
index 0000000..ac03022
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.java
@@ -0,0 +1,144 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/SecurityHelper.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/SecurityHelper.java
new file mode 100644
index 0000000..f18b422
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/SecurityHelper.java
@@ -0,0 +1,199 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java
new file mode 100644
index 0000000..030780f
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java
@@ -0,0 +1,138 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.java
new file mode 100644
index 0000000..1408554
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.java
new file mode 100644
index 0000000..b92a736
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/DigitalAssetLinksDataSource.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/DigitalAssetLinksDataSource.java
new file mode 100644
index 0000000..04624cb
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/DigitalAssetLinksDataSource.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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/PackageVerificationDataSource.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/PackageVerificationDataSource.java
new file mode 100644
index 0000000..129001d
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/PackageVerificationDataSource.java
@@ -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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.java
new file mode 100644
index 0000000..91a1923
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.java
@@ -0,0 +1,141 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsDigitalAssetLinksRepository.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsDigitalAssetLinksRepository.java
new file mode 100644
index 0000000..a8124a1
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsDigitalAssetLinksRepository.java
@@ -0,0 +1,63 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsPackageVerificationRepository.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsPackageVerificationRepository.java
new file mode 100644
index 0000000..aa46778
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsPackageVerificationRepository.java
@@ -0,0 +1,85 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.java
new file mode 100644
index 0000000..dfaa1e7
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.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.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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java
new file mode 100644
index 0000000..05956ec
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java
@@ -0,0 +1,234 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/MyPreferences.java
similarity index 95%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.java
rename to prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/MyPreferences.java
index 3926530..34d63ef 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.java
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/MyPreferences.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.example.android.autofillframework.service.settings;
+package com.example.android.autofillframework.multidatasetservice.settings;
 
 import android.content.Context;
 import android.content.SharedPreferences;
@@ -22,12 +22,9 @@
 import android.support.annotation.NonNull;
 
 public class MyPreferences {
-    private static final String TAG = "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;
 
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java
new file mode 100644
index 0000000..6ca5960
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java
@@ -0,0 +1,206 @@
+/*
+ * 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/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java
deleted file mode 100644
index 460729e..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java
+++ /dev/null
@@ -1,100 +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.service;
-
-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.util.Log;
-import android.view.autofill.AutofillId;
-import android.widget.RemoteViews;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-
-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 {
-
-    /**
-     * Wraps autofill data in a LoginCredential  Dataset object which can then be sent back to the
-     * client View.
-     */
-    public static Dataset newDataset(Context context,
-            AutofillFieldsCollection autofillFields, ClientFormData clientFormData) {
-        Dataset.Builder datasetBuilder = new Dataset.Builder
-                (newRemoteViews(context.getPackageName(), clientFormData.getDatasetName()));
-        boolean setValueAtLeastOnce = clientFormData.applyToFields(autofillFields, datasetBuilder);
-        if (setValueAtLeastOnce) {
-            return datasetBuilder.build();
-        } else {
-            return null;
-        }
-    }
-
-    public static RemoteViews newRemoteViews(String packageName, String remoteViewsText) {
-        RemoteViews presentation = new RemoteViews(packageName, R.layout.list_item);
-        presentation.setTextViewText(R.id.text1, remoteViewsText);
-        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, AutofillFieldsCollection autofillFields, int saveType,
-            HashMap<String, ClientFormData> clientFormDataMap) {
-        FillResponse.Builder responseBuilder = new FillResponse.Builder();
-        if (clientFormDataMap != null) {
-            Set<String> datasetNames = clientFormDataMap.keySet();
-            for (String datasetName : datasetNames) {
-                ClientFormData clientFormData = clientFormDataMap.get(datasetName);
-                if (datasetAuth) {
-                    Dataset.Builder datasetBuilder =
-                            new Dataset.Builder(newRemoteViews
-                                    (context.getPackageName(), clientFormData.getDatasetName()));
-                    IntentSender sender = AuthActivity
-                            .getAuthIntentSenderForDataset(context, clientFormData.getDatasetName());
-                    datasetBuilder.setAuthentication(sender);
-                    responseBuilder.addDataset(datasetBuilder.build());
-                } else {
-                    Dataset dataset = newDataset(context, autofillFields, clientFormData);
-                    if (dataset != null) {
-                        responseBuilder.addDataset(dataset);
-                    }
-                }
-            }
-        }
-        if (saveType != 0) {
-            AutofillId[] autofillIds = autofillFields.getAutofillIds();
-            responseBuilder.setSaveInfo(new SaveInfo.Builder(saveType, autofillIds).build());
-            return responseBuilder.build();
-        } else {
-            Log.d(TAG, "These fields are not meant to be saved by autofill.");
-            return null;
-        }
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java
deleted file mode 100644
index 61e4205..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java
+++ /dev/null
@@ -1,128 +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.service;
-
-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.widget.RemoteViews;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.datasource.LocalAutofillRepository;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-import com.example.android.autofillframework.service.settings.MyPreferences;
-
-import java.util.HashMap;
-import java.util.List;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-import static com.example.android.autofillframework.CommonUtil.bundleToString;
-
-public class MyAutofillService extends AutofillService {
-
-    @Override
-    public void onFillRequest(AssistStructure assistStructure, Bundle bundle, int i,
-            CancellationSignal cancellationSignal, FillCallback fillCallback) {
-        /* Deprecated, ignore */
-    }
-
-    @Override
-    public void onSaveRequest(AssistStructure assistStructure, Bundle bundle,
-            SaveCallback saveCallback) {
-        /* Deprecated, ignore */
-    }
-
-    @Override
-    public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
-            FillCallback callback) {
-        AssistStructure structure = request.getStructure();
-        final Bundle data = request.getClientState();
-        Log.d(TAG, "onFillRequest(): data=" + bundleToString(data));
-
-        // Temporary hack for disabling autofill for components in this autofill service.
-        // i.e. we don't want to autofill components in AuthActivity.
-        if (structure.getActivityComponent().toShortString()
-                .contains("com.example.android.autofillframework.service")) {
-            callback.onSuccess(null);
-            return;
-        }
-        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(structure);
-        parser.parse();
-        AutofillFieldsCollection autofillFields = parser.getAutofillFields();
-        int saveTypes = parser.getSaveTypes();
-
-        FillResponse.Builder responseBuilder = new FillResponse.Builder();
-        // Check user's settings for authenticating Responses and Datasets.
-        boolean responseAuth = MyPreferences.getInstance(this).isResponseAuth();
-        if (responseAuth) {
-            // 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));
-            responseBuilder
-                    .setAuthentication(autofillFields.getAutofillIds(), sender, presentation);
-            callback.onSuccess(responseBuilder.build());
-        } else {
-            boolean datasetAuth = MyPreferences.getInstance(this).isDatasetAuth();
-            HashMap<String, ClientFormData> clientFormDataMap =
-                    LocalAutofillRepository.getInstance(this).getClientFormData
-                            (autofillFields.getFocusedHints(), autofillFields.getAllHints());
-            FillResponse response = AutofillHelper.newResponse
-                    (this, datasetAuth, autofillFields, saveTypes, 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();
-        final Bundle data = request.getClientState();
-        Log.d(TAG, "onSaveRequest(): data=" + bundleToString(data));
-        StructureParser parser = new StructureParser(structure);
-        parser.parse();
-        ClientFormData clientFormData = parser.getClientFormData();
-        LocalAutofillRepository.getInstance(this).saveClientFormData(clientFormData);
-    }
-
-    @Override
-    public void onConnected() {
-        Log.d(TAG, "onConnected");
-    }
-
-    @Override
-    public void onDisconnected() {
-        Log.d(TAG, "onDisconnected");
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.java
deleted file mode 100644
index b629444..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.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.service;
-
-import android.app.assist.AssistStructure;
-import android.app.assist.AssistStructure.ViewNode;
-import android.app.assist.AssistStructure.WindowNode;
-import android.util.Log;
-
-import com.example.android.autofillframework.service.model.AutofillField;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-import com.example.android.autofillframework.service.model.SavedAutofillValue;
-
-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 records
- */
-final class StructureParser {
-    private final AutofillFieldsCollection mAutofillFields = new AutofillFieldsCollection();
-    private final AssistStructure mStructure;
-    private ClientFormData mClientFormData;
-
-    StructureParser(AssistStructure structure) {
-        mStructure = structure;
-
-    }
-
-    /**
-     * Traverse AssistStructure and add ViewNode metadata to a flat list.
-     */
-    void parse() {
-        Log.d(TAG, "Parsing structure for " + mStructure.getActivityComponent());
-        int nodes = mStructure.getWindowNodeCount();
-        mClientFormData = new ClientFormData();
-        for (int i = 0; i < nodes; i++) {
-            WindowNode node = mStructure.getWindowNodeAt(i);
-            ViewNode view = node.getRootViewNode();
-            parseLocked(view);
-        }
-    }
-
-    private void parseLocked(ViewNode viewNode) {
-        if (viewNode.getAutofillHints() != null && viewNode.getAutofillHints().length > 0) {
-            //TODO check to make sure hints are supported by service.
-            mAutofillFields.add(new AutofillField(viewNode));
-            mClientFormData
-                    .set(viewNode.getAutofillHints(), SavedAutofillValue.fromViewNode(viewNode));
-        }
-        int childrenSize = viewNode.getChildCount();
-        if (childrenSize > 0) {
-            for (int i = 0; i < childrenSize; i++) {
-                parseLocked(viewNode.getChildAt(i));
-            }
-        }
-    }
-
-    public AutofillFieldsCollection getAutofillFields() {
-        return mAutofillFields;
-    }
-
-    public int getSaveTypes() {
-        return mAutofillFields.getSaveType();
-    }
-
-    public ClientFormData getClientFormData() {
-        return mClientFormData;
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.java
deleted file mode 100644
index 8de8b64..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.java
+++ /dev/null
@@ -1,41 +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.service.datasource;
-
-import com.example.android.autofillframework.service.model.ClientFormData;
-
-import java.util.HashMap;
-import java.util.List;
-
-public interface AutofillRepository {
-
-    /**
-     * Gets saved ClientFormData that contains some objects that can autofill fields with these
-     * {@code autofillHints}.
-     */
-    HashMap<String, ClientFormData> getClientFormData(List<String> focusedAutofillHints,
-            List<String> allAutofillHints);
-
-    /**
-     * Saves LoginCredential under this datasetName.
-     */
-    void saveClientFormData(ClientFormData clientFormData);
-
-    /**
-     * Clears all data.
-     */
-    void clear();
-}
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java
deleted file mode 100644
index 8336fe1..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java
+++ /dev/null
@@ -1,127 +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.service.datasource;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.ArraySet;
-
-import com.example.android.autofillframework.service.model.ClientFormData;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Singleton autofill data repository, that stores autofill fields to SharedPreferences.
- * DISCLAIMER, you should not store sensitive fields like user data unencrypted. This is only done
- * here for simplicity and learning purposes.
- */
-public class LocalAutofillRepository implements AutofillRepository {
-    private static final String SHARED_PREF_KEY = "com.example.android.autofillframework.service";
-    private static final String CLIENT_FORM_DATA_KEY = "loginCredentialDatasets";
-    private static final String DATASET_NUMBER_KEY = "datasetNumber";
-
-    private static LocalAutofillRepository sInstance;
-
-    private final SharedPreferences mPrefs;
-
-    // TODO prepend with autofill data set in Settings.
-    private LocalAutofillRepository(Context context) {
-        mPrefs = context.getApplicationContext()
-                .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE);
-    }
-
-    public static LocalAutofillRepository getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new LocalAutofillRepository(context);
-        }
-        return sInstance;
-    }
-
-    @Override
-    public HashMap<String, ClientFormData> getClientFormData(List<String> focusedAutofillHints,
-            List<String> allAutofillHints) {
-        try {
-            // TODO use sqlite instead.
-            boolean hasDataForFocusedAutofillHints = false;
-            HashMap<String, ClientFormData> clientFormDataMap = new HashMap<>();
-            Set<String> clientFormDataStringSet = getAllAutofillDataStringSet();
-            for (String clientFormDataString : clientFormDataStringSet) {
-                ClientFormData clientFormData = ClientFormData
-                        .fromJson(new JSONObject(clientFormDataString));
-                if (clientFormData != null) {
-                    if (clientFormData.helpsWithHints(focusedAutofillHints)) {
-                        hasDataForFocusedAutofillHints = true;
-                    }
-                    if (clientFormData.helpsWithHints(allAutofillHints)) {
-                        clientFormDataMap.put(clientFormData.getDatasetName(), clientFormData);
-                    }
-                }
-            }
-            if (hasDataForFocusedAutofillHints) {
-                return clientFormDataMap;
-            } else {
-                return null;
-            }
-        } catch (JSONException e) {
-            return null;
-        }
-    }
-
-    @Override
-    public void saveClientFormData(ClientFormData clientFormData) {
-        //TODO use sqlite instead.
-        String datasetName = "dataset-" + getDatasetNumber();
-        clientFormData.setDatasetName(datasetName);
-        Set<String> allAutofillData = getAllAutofillDataStringSet();
-        allAutofillData.add(clientFormData.toJson().toString());
-        saveAllAutofillDataStringSet(allAutofillData);
-        incrementDatasetNumber();
-    }
-
-    @Override
-    public void clear() {
-        mPrefs.edit().remove(CLIENT_FORM_DATA_KEY).apply();
-    }
-
-    private Set<String> getAllAutofillDataStringSet() {
-        return mPrefs.getStringSet(CLIENT_FORM_DATA_KEY, new ArraySet<String>());
-    }
-
-    private void saveAllAutofillDataStringSet(Set<String> allAutofillDataStringSet) {
-        mPrefs.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() {
-        return mPrefs.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() {
-        mPrefs.edit().putInt(DATASET_NUMBER_KEY, getDatasetNumber() + 1).apply();
-    }
-}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java
deleted file mode 100644
index 4d4de2b..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java
+++ /dev/null
@@ -1,120 +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.service.model;
-
-import android.app.assist.AssistStructure;
-import android.service.autofill.SaveInfo;
-import android.view.View;
-import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillValue;
-
-/**
- * Class that represents a field that can be autofilled. It will contain a description
- * (what type data the field holds), an AutoFillId (an ID unique to the rest of the ViewStructure),
- * and a value (what data is currently in the field).
- */
-public class AutofillField {
-    private int mSaveType = 0;
-    private String[] mHints;
-    private AutofillId mId;
-    private int mAutofillType;
-    private String[] mAutofillOptions;
-    private boolean mFocused;
-
-    public AutofillField(AssistStructure.ViewNode view) {
-        mId = view.getAutofillId();
-        setHints(view.getAutofillHints());
-        mAutofillType = view.getAutofillType();
-        mAutofillOptions = view.getAutofillOptions();
-        mFocused = view.isFocused();
-    }
-
-    public String[] getHints() {
-        return mHints;
-    }
-
-    public void setHints(String[] hints) {
-        mHints = hints;
-        updateSaveTypeFromHints();
-    }
-
-    public int getSaveType() {
-        return mSaveType;
-    }
-
-    public AutofillId getId() {
-        return mId;
-    }
-
-    public void setId(AutofillId id) {
-        mId = id;
-    }
-
-    public int getAutofillType() {
-        return mAutofillType;
-    }
-
-    public int getAutofillOptionIndex(String value) {
-        for (int i = 0; i < mAutofillOptions.length; i++) {
-            if (mAutofillOptions[i].equals(value)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    public boolean isFocused() {
-        return mFocused;
-    }
-
-    private void updateSaveTypeFromHints() {
-        mSaveType = 0;
-        if (mHints == null) {
-            return;
-        }
-        for (String hint : mHints) {
-            switch (hint) {
-                case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE:
-                case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY:
-                case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH:
-                case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR:
-                case View.AUTOFILL_HINT_CREDIT_CARD_NUMBER:
-                case View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
-                    break;
-                case View.AUTOFILL_HINT_EMAIL_ADDRESS:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
-                    break;
-                case View.AUTOFILL_HINT_PHONE:
-                case View.AUTOFILL_HINT_NAME:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_GENERIC;
-                    break;
-                case View.AUTOFILL_HINT_PASSWORD:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_PASSWORD;
-                    mSaveType &= ~SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
-                    mSaveType &= ~SaveInfo.SAVE_DATA_TYPE_USERNAME;
-                    break;
-                case View.AUTOFILL_HINT_POSTAL_ADDRESS:
-                case View.AUTOFILL_HINT_POSTAL_CODE:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_ADDRESS;
-                    break;
-                case View.AUTOFILL_HINT_USERNAME:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_USERNAME;
-                    break;
-            }
-        }
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java
deleted file mode 100644
index aa57e93..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java
+++ /dev/null
@@ -1,184 +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.service.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 org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-/**
- * ClientFormData 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 ClientFormData {
-    private static final String TAG = "ClientFormData";
-    private final HashMap<String, SavedAutofillValue> hintMap;
-    private String datasetName;
-
-    public ClientFormData() {
-        this(null, new HashMap<String, SavedAutofillValue>());
-    }
-
-    public ClientFormData(String datasetName, HashMap<String, SavedAutofillValue> hintMap) {
-        this.hintMap = hintMap;
-        this.datasetName = datasetName;
-    }
-
-    public static ClientFormData fromJson(JSONObject jsonObject) {
-        HashMap<String, SavedAutofillValue> hintMap = new HashMap<>();
-        try {
-            String datasetName = jsonObject.has("datasetName") ?
-                    jsonObject.getString("datasetName") : null;
-            JSONObject valuesJson = jsonObject.getJSONObject("values");
-            Iterator<String> hints = valuesJson.keys();
-            while (hints.hasNext()) {
-                String hint = hints.next();
-                JSONObject valueAsJson = valuesJson
-                        .getJSONObject(hint);
-                if (valueAsJson != null) {
-                    SavedAutofillValue savedAutofillValue = SavedAutofillValue.fromJson(valueAsJson);
-                    hintMap.put(hint, savedAutofillValue);
-                }
-            }
-            return new ClientFormData(datasetName, hintMap);
-        } catch (JSONException e) {
-            Log.d(TAG, e.getMessage());
-            return null;
-        }
-    }
-
-    /**
-     * Returns the name of the {@link Dataset}.
-     */
-    public String getDatasetName() {
-        return this.datasetName;
-    }
-
-    /**
-     * Sets the {@link Dataset} name.
-     */
-    public void setDatasetName(String datasetName) {
-        this.datasetName = datasetName;
-    }
-
-    /**
-     * Sets values for a list of hints.
-     */
-    public void set(@NonNull String[] autofillHints, @NonNull SavedAutofillValue autofillValue) {
-        if (autofillHints.length < 1) {
-            return;
-        }
-        for (int i = 0; i < autofillHints.length; i++) {
-            hintMap.put(autofillHints[i], autofillValue);
-        }
-    }
-
-    /**
-     * Populates a {@link Dataset.Builder} with appropriate values for each {@link AutofillId}
-     * in a {@code AutofillFieldsCollection}.
-     */
-    public boolean applyToFields(AutofillFieldsCollection autofillFieldsCollection,
-            Dataset.Builder datasetBuilder) {
-        boolean setValueAtLeastOnce = false;
-        List<String> allHints = autofillFieldsCollection.getAllHints();
-        for (int hintIndex = 0; hintIndex < allHints.size(); hintIndex++) {
-            String hint = allHints.get(hintIndex);
-            List<AutofillField> autofillFields = autofillFieldsCollection.getFieldsForHint(hint);
-            if (autofillFields == null) {
-                continue;
-            }
-            for (int autofillFieldIndex = 0; autofillFieldIndex < autofillFields.size(); autofillFieldIndex++) {
-                AutofillField autofillField = autofillFields.get(autofillFieldIndex);
-                AutofillId autofillId = autofillField.getId();
-                int autofillType = autofillField.getAutofillType();
-                SavedAutofillValue savedAutofillValue = hintMap.get(hint);
-                switch (autofillType) {
-                    case View.AUTOFILL_TYPE_LIST:
-                        int listValue = autofillField.getAutofillOptionIndex(savedAutofillValue.getTextValue());
-                        if (listValue != -1) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forList(listValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_DATE:
-                        long dateValue = savedAutofillValue.getDateValue();
-                        if (dateValue != -1) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forDate(dateValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_TEXT:
-                        String textValue = savedAutofillValue.getTextValue();
-                        if (textValue != null) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forText(textValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_TOGGLE:
-                        if (savedAutofillValue.hasToggleValue()) {
-                            boolean toggleValue = savedAutofillValue.getToggleValue();
-                            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;
-    }
-
-    public JSONObject toJson() {
-        JSONObject jsonObject = new JSONObject();
-        try {
-            jsonObject.put("datasetName", datasetName != null ? datasetName : JSONObject.NULL);
-            JSONObject jsonValues = new JSONObject();
-            Set<String> hints = hintMap.keySet();
-            for (String hint : hints) {
-                SavedAutofillValue value = hintMap.get(hint);
-                jsonValues.put(hint, value != null ? value.toJson() : JSONObject.NULL);
-            }
-            jsonObject.put("values", jsonValues);
-        } catch (JSONException e) {
-            Log.e(TAG, e.getMessage());
-        }
-        return jsonObject;
-    }
-
-    public boolean helpsWithHints(List<String> autofillHints) {
-        for (int i = 0; i < autofillHints.size(); i++) {
-            String autofillHint = autofillHints.get(i);
-            if (hintMap.get(autofillHint) != null && !hintMap.get(autofillHint).isNull()) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.java
deleted file mode 100644
index 73e0c81..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.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.service.model;
-
-import android.app.assist.AssistStructure;
-import android.util.Log;
-import android.view.autofill.AutofillValue;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-public class SavedAutofillValue {
-    private static final String TAG = "SavedAutofillValue";
-    private String textValue = null;
-    private Long dateValue = -1L;
-    private Boolean toggleValue = false;
-    private boolean hasToggleValue = false;
-
-    public static SavedAutofillValue fromJson(JSONObject jsonObject) {
-        if (jsonObject == null) {
-            return null;
-        }
-        try {
-            SavedAutofillValue savedAutofillValue = new SavedAutofillValue();
-
-            savedAutofillValue.textValue =
-                    !jsonObject.isNull("textValue") ? jsonObject.getString("textValue") : null;
-            savedAutofillValue.dateValue =
-                    !jsonObject.isNull("dateValue") ? jsonObject.getLong("dateValue") : null;
-            savedAutofillValue.setToggleValue
-                    (!jsonObject.isNull("toggleValue") ? jsonObject.getBoolean("toggleValue") : null);
-            return savedAutofillValue;
-        } catch (JSONException e) {
-            Log.e(TAG, e.getMessage());
-            return null;
-        }
-    }
-
-    public static SavedAutofillValue fromViewNode(AssistStructure.ViewNode viewNode) {
-        SavedAutofillValue savedAutofillValue = new SavedAutofillValue();
-        AutofillValue autofillValue = viewNode.getAutofillValue();
-        if (autofillValue != null) {
-            if (autofillValue.isList()) {
-                String[] autofillOptions = viewNode.getAutofillOptions();
-                int index = autofillValue.getListValue();
-                if (autofillOptions != null && autofillOptions.length > 0) {
-                    savedAutofillValue.textValue = autofillOptions[index];
-                }
-            } else if (autofillValue.isDate()) {
-                savedAutofillValue.dateValue = autofillValue.getDateValue();
-            } else if (autofillValue.isText()) {
-                // Using toString of AutofillValue.getTextValue in order to save it to
-                // SharedPreferences.
-                savedAutofillValue.textValue = autofillValue.getTextValue().toString();
-            }
-        }
-        return savedAutofillValue;
-    }
-
-    public JSONObject toJson() {
-        JSONObject jsonObject = new JSONObject();
-        try {
-            jsonObject.put("textValue", textValue != null ? textValue : JSONObject.NULL);
-            jsonObject.put("dateValue", dateValue != null ? dateValue : JSONObject.NULL);
-            jsonObject.put("toggleValue", toggleValue != null ? toggleValue : JSONObject.NULL);
-            return jsonObject;
-        } catch (JSONException e) {
-            Log.e(TAG, e.getMessage());
-            return null;
-        }
-    }
-
-    public String getTextValue() {
-        return textValue;
-    }
-
-    public long getDateValue() {
-        return dateValue;
-    }
-
-
-    public boolean getToggleValue() {
-        return toggleValue;
-    }
-
-    public void setToggleValue(Boolean toggleValue) {
-        this.toggleValue = toggleValue;
-        hasToggleValue = toggleValue != null;
-    }
-
-
-    public boolean isNull() {
-        return textValue == null && dateValue == -1L && !hasToggleValue;
-    }
-
-    public boolean hasToggleValue() {
-        return hasToggleValue;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        SavedAutofillValue that = (SavedAutofillValue) o;
-
-        if (textValue != null ? !textValue.equals(that.textValue) : that.textValue != null)
-            return false;
-        if (dateValue != null ? !dateValue.equals(that.dateValue) : that.dateValue != null)
-            return false;
-        return toggleValue != null ? toggleValue.equals(that.toggleValue) : that.toggleValue == null;
-
-    }
-
-    @Override
-    public int hashCode() {
-        int result = textValue != null ? textValue.hashCode() : 0;
-        result = 31 * result + (dateValue != null ? dateValue.hashCode() : 0);
-        result = 31 * result + (toggleValue != null ? toggleValue.hashCode() : 0);
-        return result;
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java b/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java
deleted file mode 100644
index 6387d36..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java
+++ /dev/null
@@ -1,176 +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.service.settings;
-
-import android.content.DialogInterface;
-import android.os.Bundle;
-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.widget.CompoundButton;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.datasource.LocalAutofillRepository;
-
-public class SettingsActivity extends AppCompatActivity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.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(),
-                new CompoundButton.OnCheckedChangeListener() {
-                    @Override
-                    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
-                        preferences.setResponseAuth(b);
-                    }
-                });
-        setupSettingsSwitch(R.id.settings_auth_datasets_container,
-                R.id.settings_auth_datasets_label,
-                R.id.settings_auth_datasets_switch,
-                preferences.isDatasetAuth(),
-                new CompoundButton.OnCheckedChangeListener() {
-                    @Override
-                    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
-                        preferences.setDatasetAuth(b);
-                    }
-                });
-        setupSettingsButton(R.id.settings_clear_data_container,
-                R.id.settings_clear_data_label,
-                R.id.settings_clear_data_icon,
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        buildClearDataDialog().show();
-                    }
-                });
-
-        setupSettingsButton(R.id.settings_auth_credentials_container,
-                R.id.settings_auth_credentials_label,
-                R.id.settings_auth_credentials_icon,
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View 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, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        LocalAutofillRepository.getInstance
-                                (SettingsActivity.this).clear();
-                        MyPreferences.getInstance(SettingsActivity.this)
-                                .clearCredentials();
-                        dialog.dismiss();
-                    }
-                })
-                .create();
-    }
-
-    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.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.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, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int 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 = (ViewGroup) findViewById(containerId);
-        String switchLabel = ((TextView) container.findViewById(labelId)).getText().toString();
-        final Switch switchView = container.findViewById(switchId);
-        switchView.setContentDescription(switchLabel);
-        switchView.setChecked(checked);
-        container.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                switchView.performClick();
-            }
-        });
-        switchView.setOnCheckedChangeListener(checkedChangeListener);
-    }
-
-    private void setupSettingsButton(int containerId, int labelId, int imageViewId,
-            final View.OnClickListener onClickListener) {
-        ViewGroup container = (ViewGroup) findViewById(containerId);
-        String buttonLabel = ((TextView) container.findViewById(labelId)).getText().toString();
-        final ImageView imageView = container.findViewById(imageViewId);
-        imageView.setContentDescription(buttonLabel);
-        container.setOnClickListener(onClickListener);
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_add_black_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_add_black_24dp.xml
new file mode 100644
index 0000000..e50269d
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/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:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_autocomplete_logo_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_autocomplete_logo_24dp.xml
new file mode 100644
index 0000000..80f30a2
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_autocomplete_logo_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_custom_virtual_logo_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_custom_virtual_logo_24dp.xml
new file mode 100644
index 0000000..3a8ee3b
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_custom_virtual_logo_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_edittexts_logo_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_edittexts_logo_24dp.xml
new file mode 100644
index 0000000..17e403d
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_edittexts_logo_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:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M4,9h16v2L4,11zM4,13h10v2L4,15z"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_email_black_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_email_black_24dp.xml
new file mode 100644
index 0000000..174c127
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_email_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_info_black_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_info_black_24dp.xml
new file mode 100644
index 0000000..c297121
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_info_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_lock_black_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_lock_black_24dp.xml
new file mode 100644
index 0000000..6b2f014
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/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: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/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_send_white_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_send_white_24dp.xml
new file mode 100644
index 0000000..f614267
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_send_white_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:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_spinners_logo_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_spinners_logo_24dp.xml
new file mode 100644
index 0000000..5fb27a2
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_spinners_logo_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_view_module_black_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_view_module_black_24dp.xml
new file mode 100644
index 0000000..ab36b07
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_view_module_black_24dp.xml
@@ -0,0 +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">
+    <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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_web_black_24dp.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_web_black_24dp.xml
new file mode 100644
index 0000000..48e7b7b
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/drawable/ic_web_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/activity_main.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/activity_main.xml
index 26d0657..687308e 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/activity_main.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/activity_main.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,33 +13,118 @@
  * 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/activity_vertical_margin"
-              android:paddingRight="@dimen/activity_horizontal_margin"
-              android:paddingStart="@dimen/activity_horizontal_margin"
-              android:paddingTop="@dimen/activity_vertical_margin">
+<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">
 
-    <Button
-        android:id="@+id/standardViewSignInButton"
+    <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:text="@string/standard_view_sign_in" />
+        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">
 
-    <Button
-        android:id="@+id/virtualViewSignInButton"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/activity_vertical_margin"
-        android:text="@string/virtual_view_sign_in" />
+        <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" />
 
-    <Button
-        android:id="@+id/creditCardCheckoutButton"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/activity_vertical_margin"
-        android:text="@string/credit_card_checkout" />
+        <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" />
 
-</LinearLayout>
\ No newline at end of file
+        <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
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/auth_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/auth_activity.xml
deleted file mode 100644
index 4b5926a..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/auth_activity.xml
+++ /dev/null
@@ -1,62 +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"
-              xmlns:tools="http://schemas.android.com/tools"
-              android:id="@+id/authLayout"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              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=".service.AuthActivity">
-
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:text="Master password">
-    </TextView>
-
-    <EditText
-        android:id="@+id/master_password"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:inputType="textPassword">
-    </EditText>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center"
-        android:orientation="horizontal">
-
-        <Button
-            android:id="@+id/cancel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Cancel" />
-
-        <Button
-            android:id="@+id/login"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Login" />
-    </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/cc_exp_date.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/cc_exp_date.xml
new file mode 100644
index 0000000..a4dd537
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/cc_exp_date.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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <android.support.constraint.ConstraintLayout
+        android:id="@+id/navigation_item_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <Spinner
+            android:id="@+id/ccExpMonth"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="8dp"
+            android:contentDescription="@string/cc_exp_month_description"
+            app:layout_constraintBottom_toBottomOf="@+id/monthYearDelimiter"
+            app:layout_constraintEnd_toStartOf="@+id/monthYearDelimiter"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/monthYearDelimiter" />
+
+        <TextView
+            android:id="@+id/monthYearDelimiter"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/slash"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/ccExpYear"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toEndOf="@+id/ccExpMonth"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <Spinner
+            android:id="@+id/ccExpYear"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:contentDescription="@string/cc_exp_year_description"
+            app:layout_constraintBottom_toBottomOf="@+id/monthYearDelimiter"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toEndOf="@+id/monthYearDelimiter"
+            app:layout_constraintTop_toTopOf="@+id/monthYearDelimiter" />
+    </android.support.constraint.ConstraintLayout>
+</merge>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_activity.xml
index 7d8e099..e2075ef 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_activity.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_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,95 +13,198 @@
  * 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/standardLoginLayout"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:focusable="true"
-              android:focusableInTouchMode="true"
-              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">
+<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"
+    android:layout_height="match_parent"
+    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">
 
-    <RelativeLayout
+    <TextView
+        android:id="@+id/creditCardHeader"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_credit_card_label"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center">
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/anti_pattern_credit_card_info"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardHeader"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/creditCardHeader"
+        app:layout_constraintTop_toTopOf="@+id/creditCardHeader" />
 
-        <TextView
-            android:id="@+id/creditCardNumberLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="20dp"
-            android:importantForAutofill="no"
-            android:text="@string/credit_card_number_label" />
-
-        <EditText
-            android:id="@+id/creditCardNumberField"
-            android:layout_width="200sp"
-            android:layout_height="wrap_content"
-            android:layout_alignBaseline="@+id/creditCardNumberLabel"
-            android:layout_toEndOf="@id/creditCardNumberLabel"
-            android:autofillHints="creditCardNumber" />
-
-        <TextView
-            android:id="@+id/creditCardExpirationLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignStart="@+id/creditCardNumberLabel"
-            android:layout_below="@+id/creditCardNumberLabel"
-            android:layout_marginTop="20dp"
-            android:importantForAutofill="no"
-            android:text="@string/credit_card_expiration_label" />
-
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignBaseline="@+id/creditCardExpirationLabel"
-            android:layout_alignStart="@+id/creditCardNumberField"
-            android:orientation="horizontal">
-
-            <Spinner
-                android:id="@+id/expirationDay"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:autofillHints="creditCardExpirationDay" />
-
-            <Spinner
-                android:id="@+id/expirationMonth"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:autofillHints="creditCardExpirationMonth" />
-
-            <Spinner
-                android:id="@+id/expirationYear"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:autofillHints="creditCardExpirationYear" />
-        </LinearLayout>
-
-    </RelativeLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
+    <TextView
+        android:id="@+id/creditCardNumberLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
-        android:gravity="center"
-        android:orientation="horizontal">
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/creditCardNumberField"
+        android:text="@string/credit_card_number_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardHeader" />
 
-        <Button
-            android:id="@+id/clear"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Clear" />
+    <EditText
+        android:id="@+id/creditCardNumberField"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:autofillHints="creditCardNumber"
+        android:ems="10"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardNumberLabel"
+        app:layout_constraintStart_toEndOf="@+id/expirationMonthLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardNumberLabel" />
 
-        <Button
-            android:id="@+id/submit"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Submit" />
-    </LinearLayout>
+    <TextView
+        android:id="@+id/expirationDayLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:labelFor="@+id/expirationDay"
+        android:text="@string/credit_card_expiration_day_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardNumberLabel" />
 
-</LinearLayout>
\ No newline at end of file
+    <EditText
+        android:id="@+id/expirationDay"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/expirationDayLabel"
+        android:layout_marginEnd="8dp"
+        android:autofillHints="creditCardExpirationDay"
+        android:ems="6"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/expirationDayLabel"
+        app:layout_constraintStart_toEndOf="@+id/expirationMonthLabel"
+        app:layout_constraintTop_toTopOf="@+id/expirationDayLabel" />
+
+    <TextView
+        android:id="@+id/expirationMonthLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:labelFor="@+id/expirationMonth"
+        android:paddingEnd="@dimen/padding_normal"
+        android:text="@string/credit_card_expiration_month_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/expirationDay" />
+
+    <EditText
+        android:id="@+id/expirationMonth"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/expirationMonthLabel"
+        android:layout_marginEnd="8dp"
+        android:autofillHints="creditCardExpirationMonth"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/expirationMonthLabel"
+        app:layout_constraintEnd_toEndOf="@+id/expirationDay"
+        app:layout_constraintStart_toStartOf="@+id/expirationDay"
+        app:layout_constraintTop_toTopOf="@+id/expirationMonthLabel" />
+
+    <TextView
+        android:id="@+id/expirationYearLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:labelFor="@+id/expirationYear"
+        android:text="@string/credit_card_expiration_year_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/expirationMonth" />
+
+    <EditText
+        android:id="@+id/expirationYear"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/expirationYearLabel"
+        android:layout_marginEnd="8dp"
+        android:autofillHints="creditCardExpirationYear"
+        android:ems="6"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/expirationYearLabel"
+        app:layout_constraintStart_toEndOf="@+id/expirationMonthLabel"
+        app:layout_constraintTop_toTopOf="@+id/expirationYearLabel" />
+
+    <TextView
+        android:id="@+id/creditCardSecurityCodeLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:labelFor="@+id/creditCardSecurityCode"
+        android:text="@string/credit_card_security_code_abbrev_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/expirationYear" />
+
+    <EditText
+        android:id="@+id/creditCardSecurityCode"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/creditCardSecurityCodeLabel"
+        android:layout_marginEnd="8dp"
+        android:autofillHints="creditCardSecurityCode"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintEnd_toEndOf="@+id/expirationYear"
+        app:layout_constraintStart_toStartOf="@+id/expirationYear"
+        app:layout_constraintTop_toTopOf="@+id/creditCardSecurityCodeLabel" />
+
+    <TextView
+        android:id="@+id/clearButton"
+        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/clear_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toStartOf="@+id/submitButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardSecurityCode" />
+
+    <TextView
+        android:id="@+id/submitButton"
+        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/submit_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/clearButton"
+        app:layout_constraintTop_toTopOf="@+id/clearButton" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_anti_pattern_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_anti_pattern_activity.xml
new file mode 100644
index 0000000..8b9f396
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_anti_pattern_activity.xml
@@ -0,0 +1,155 @@
+<?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"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    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">
+
+    <TextView
+        android:id="@+id/creditCardHeader"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:gravity="center"
+        android:text="@string/navigation_button_anti_pattern_credit_card_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/infoButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/anti_pattern_credit_card_info"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardHeader"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/creditCardHeader"
+        app:layout_constraintTop_toTopOf="@+id/creditCardHeader" />
+
+    <TextView
+        android:id="@+id/creditCardNumberLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/creditCardNumberField"
+        android:text="@string/credit_card_number_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardHeader" />
+
+    <EditText
+        android:id="@+id/creditCardNumberField"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:autofillHints="creditCardNumber"
+        android:ems="12"
+        android:inputType="number"
+        android:paddingHorizontal="@dimen/spacing_micro"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardNumberLabel"
+        app:layout_constraintStart_toEndOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardNumberLabel" />
+
+    <TextView
+        android:id="@+id/creditCardExpirationLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/creditCardExpirationView"
+        android:text="@string/credit_card_expiration_label"
+        app:layout_constraintStart_toStartOf="@id/creditCardNumberLabel"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardNumberLabel" />
+
+    <EditText
+        android:id="@+id/creditCardExpirationView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:autofillHints="creditCardExpirationDate"
+        android:ems="12"
+        android:paddingHorizontal="@dimen/spacing_micro"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintLeft_toRightOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintStart_toEndOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardExpirationLabel" />
+
+    <TextView
+        android:id="@+id/creditCardSecurityCodeLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:labelFor="@+id/creditCardSecurityCode"
+        android:paddingEnd="@dimen/padding_normal"
+        android:paddingRight="@dimen/padding_normal"
+        android:text="@string/credit_card_security_code_label"
+        app:layout_constraintStart_toStartOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardExpirationView" />
+
+    <EditText
+        android:id="@+id/creditCardSecurityCode"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:autofillHints="creditCardSecurityCode"
+        android:ems="6"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintStart_toEndOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardSecurityCodeLabel" />
+
+    <TextView
+        android:id="@+id/clearButton"
+        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/clear_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toStartOf="@+id/submitButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardSecurityCode" />
+
+    <TextView
+        android:id="@+id/submitButton"
+        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/submit_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/clearButton"
+        app:layout_constraintTop_toTopOf="@+id/clearButton" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_compound_view_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_compound_view_activity.xml
new file mode 100644
index 0000000..9298704
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_compound_view_activity.xml
@@ -0,0 +1,156 @@
+<?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"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    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">
+
+    <TextView
+        android:id="@+id/creditCardHeader"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_compound_view_credit_card_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/compound_view_credit_card_info"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardHeader"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/creditCardHeader"
+        app:layout_constraintTop_toTopOf="@+id/creditCardHeader" />
+
+    <TextView
+        android:id="@+id/creditCardNumberLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/creditCardNumberField"
+        android:text="@string/credit_card_number_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardHeader" />
+
+    <EditText
+        android:id="@+id/creditCardNumberField"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:autofillHints="creditCardNumber"
+        android:ems="12"
+        android:inputType="number"
+        android:paddingHorizontal="@dimen/spacing_micro"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardNumberLabel"
+        app:layout_constraintStart_toEndOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardNumberLabel" />
+
+    <TextView
+        android:id="@+id/creditCardExpirationLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/creditCardExpirationView"
+        android:text="@string/credit_card_expiration_label"
+        app:layout_constraintStart_toStartOf="@id/creditCardNumberLabel"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardNumberLabel" />
+
+    <com.example.android.autofillframework.app.CreditCardExpirationDateCompoundView
+        android:id="@+id/creditCardExpirationView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:autofillHints="creditCardExpirationDate"
+        android:ems="12"
+        android:paddingHorizontal="@dimen/spacing_micro"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintLeft_toRightOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintStart_toEndOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardExpirationLabel" />
+
+    <TextView
+        android:id="@+id/creditCardSecurityCodeLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:labelFor="@+id/creditCardSecurityCode"
+        android:paddingEnd="@dimen/padding_normal"
+        android:paddingRight="@dimen/padding_normal"
+        android:text="@string/credit_card_security_code_abbrev_label"
+        app:layout_constraintStart_toStartOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardExpirationLabel" />
+
+    <EditText
+        android:id="@+id/creditCardSecurityCode"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:autofillHints="creditCardSecurityCode"
+        android:ems="6"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintStart_toEndOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardSecurityCodeLabel" />
+
+    <TextView
+        android:id="@+id/clearButton"
+        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/clear_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toStartOf="@+id/submitButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardSecurityCodeLabel" />
+
+    <TextView
+        android:id="@+id/submitButton"
+        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/submit_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/clearButton"
+        app:layout_constraintTop_toTopOf="@+id/clearButton" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_date_picker_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_date_picker_activity.xml
new file mode 100644
index 0000000..70e3cb5
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_date_picker_activity.xml
@@ -0,0 +1,162 @@
+<?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"
+    android:id="@+id/authLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    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">
+
+    <TextView
+        android:id="@+id/standard_login_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_date_picker_credit_card_label"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/date_picker_credit_card_info"
+        app:layout_constraintBottom_toBottomOf="@+id/standard_login_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/standard_login_header"
+        app:layout_constraintTop_toTopOf="@+id/standard_login_header" />
+
+    <TextView
+        android:id="@+id/creditCardNumberLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/creditCardNumberField"
+        android:text="@string/credit_card_number_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/standard_login_header" />
+
+    <EditText
+        android:id="@+id/creditCardNumberField"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:autofillHints="creditCardNumber"
+        android:ems="10"
+        android:inputType="number"
+        android:paddingHorizontal="@dimen/spacing_micro"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardNumberLabel"
+        app:layout_constraintStart_toEndOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardNumberLabel" />
+
+    <TextView
+        android:id="@+id/creditCardExpirationLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/creditCardExpirationView"
+        android:text="@string/credit_card_expiration_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardNumberLabel" />
+
+    <com.example.android.autofillframework.app.CreditCardExpirationDatePickerView
+        android:id="@+id/creditCardExpirationView"
+        android:layout_width="250dp"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:autofillHints="creditCardExpirationDate"
+        android:onClick="showDatePickerDialog"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardExpirationLabel" />
+
+    <TextView
+        android:id="@+id/creditCardSecurityCodeLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        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"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardExpirationView" />
+
+    <EditText
+        android:id="@+id/creditCardSecurityCode"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/creditCardSecurityCodeLabel"
+        android:layout_marginEnd="8dp"
+        android:layout_marginStart="8dp"
+        android:autofillHints="creditCardSecurityCode"
+        android:inputType="number"
+        android:ems="6"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintStart_toEndOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardSecurityCodeLabel" />
+
+    <TextView
+        android:id="@+id/clearButton"
+        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_large"
+        android:text="@string/clear_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toStartOf="@+id/submitButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardSecurityCodeLabel" />
+
+    <TextView
+        android:id="@+id/submitButton"
+        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/submit_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/clearButton"
+        app:layout_constraintTop_toTopOf="@+id/clearButton" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_spinners_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_spinners_activity.xml
new file mode 100644
index 0000000..1034ca2
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/credit_card_spinners_activity.xml
@@ -0,0 +1,172 @@
+<?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"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin">
+
+    <TextView
+        android:id="@+id/creditCardHeader"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_spinners_credit_card_label"
+        app:layout_constraintEnd_toStartOf="@+id/infoButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/infoButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/spinners_credit_card_info"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardHeader"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/creditCardHeader"
+        app:layout_constraintTop_toTopOf="@+id/creditCardHeader" />
+
+    <TextView
+        android:id="@+id/creditCardNumberLabel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:labelFor="@+id/creditCardNumberField"
+        android:text="@string/credit_card_number_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardHeader" />
+
+    <EditText
+        android:id="@+id/creditCardNumberField"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/creditCardNumberLabel"
+        android:autofillHints="creditCardNumber"
+        android:ems="10"
+        android:focusedByDefault="true"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardNumberLabel"
+        app:layout_constraintLeft_toRightOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintStart_toStartOf="@+id/expirationDay"
+        app:layout_constraintTop_toTopOf="@+id/creditCardNumberLabel" />
+
+    <TextView
+        android:id="@+id/creditCardExpirationLabel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:text="@string/credit_card_expiration_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardNumberLabel" />
+
+    <Spinner
+        android:id="@+id/expirationDay"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:autofillHints="creditCardExpirationDay"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintEnd_toStartOf="@+id/expirationMonth"
+        app:layout_constraintStart_toEndOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardExpirationLabel" />
+
+    <Spinner
+        android:id="@+id/expirationMonth"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:autofillHints="creditCardExpirationMonth"
+        app:layout_constraintBottom_toBottomOf="@+id/expirationDay"
+        app:layout_constraintEnd_toStartOf="@+id/expirationYear"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/expirationDay"
+        app:layout_constraintTop_toTopOf="@+id/expirationDay" />
+
+    <Spinner
+        android:id="@+id/expirationYear"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:autofillHints="creditCardExpirationYear"
+        app:layout_constraintBottom_toBottomOf="@+id/expirationMonth"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/expirationMonth"
+        app:layout_constraintTop_toTopOf="@+id/expirationMonth" />
+
+    <TextView
+        android:id="@+id/creditCardSecurityCodeLabel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:labelFor="@+id/creditCardSecurityCode"
+        android:text="@string/credit_card_security_code_abbrev_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardExpirationLabel" />
+
+    <EditText
+        android:id="@+id/creditCardSecurityCode"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/creditCardSecurityCodeLabel"
+        android:autofillHints="creditCardSecurityCode"
+        android:ems="6"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardSecurityCodeLabel"
+        app:layout_constraintStart_toStartOf="@+id/expirationDay"
+        app:layout_constraintTop_toTopOf="@+id/creditCardSecurityCodeLabel" />
+
+    <TextView
+        android:id="@+id/clear"
+        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_large"
+        android:text="@string/clear_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toStartOf="@+id/submit"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardSecurityCodeLabel" />
+
+    <TextView
+        android:id="@+id/submit"
+        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/submit_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/clear"
+        app:layout_constraintTop_toTopOf="@+id/clear" />
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/email_compose_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/email_compose_activity.xml
new file mode 100644
index 0000000..5df3fdc
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/email_compose_activity.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.
+-->
+<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"
+    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">
+
+    <TextView
+        android:id="@+id/email_compose_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:gravity="center"
+        android:text="@string/navigation_button_email_compose_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/email_compose_info"
+        app:layout_constraintBottom_toBottomOf="@+id/email_compose_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/email_compose_header"
+        app:layout_constraintTop_toTopOf="@+id/email_compose_header" />
+
+    <TextView
+        android:id="@+id/toLabel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/spacing_normal"
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:text="@string/to_label"
+        app:layout_constraintBottom_toBottomOf="@+id/toText"
+        app:layout_constraintEnd_toStartOf="@+id/toText"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/toText" />
+
+    <EditText
+        android:id="@+id/toText"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:inputType="textEmailAddress"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="@+id/bodyText"
+        app:layout_constraintTop_toBottomOf="@+id/email_compose_header" />
+
+    <TextView
+        android:id="@+id/bodyLabel"
+        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/body_label"
+        app:layout_constraintBottom_toBottomOf="@+id/placeholder"
+        app:layout_constraintEnd_toStartOf="@+id/bodyText"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/placeholder" />
+
+    <EditText
+        android:id="@+id/bodyText"
+        android:layout_width="0dp"
+        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="textMultiLine"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/bodyLabel"
+        app:layout_constraintTop_toBottomOf="@+id/toText" />
+
+    <View
+        android:id="@+id/placeholder"
+        android:layout_width="match_parent"
+        android:layout_height="36sp"
+        android:layout_marginStart="8dp"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/bodyText" />
+
+    <android.support.design.widget.FloatingActionButton
+        android:id="@+id/sendButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="8dp"
+        android:layout_marginEnd="8dp"
+        android:backgroundTint="@android:color/holo_purple"
+        android:src="@drawable/ic_send_white_24dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/list_item.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/list_item.xml
deleted file mode 100644
index d01bc37..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/list_item.xml
+++ /dev/null
@@ -1,26 +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.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-          android:id="@+id/text1"
-          android:layout_width="fill_parent"
-          android:layout_height="fill_parent"
-          android:background="#ffffffff"
-          android:gravity="center_vertical"
-          android:minHeight="?android:attr/listPreferredItemHeightSmall"
-          android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-          android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-          android:textAppearance="?android:attr/textAppearanceListItemSmall" />
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_activity.xml
index 6382fe7..ce70e1d 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_activity.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_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,78 +13,131 @@
  * 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/standardLoginLayout"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:focusable="true"
-              android:focusableInTouchMode="true"
-              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">
+<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"
+    android:layout_height="match_parent"
+    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">
 
-    <RelativeLayout
+    <TextView
+        android:id="@+id/standard_login_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_edittext_login_label"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center">
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/edittext_login_info"
+        app:layout_constraintBottom_toBottomOf="@+id/standard_login_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/standard_login_header"
+        app:layout_constraintTop_toTopOf="@+id/standard_login_header" />
 
-        <TextView
-            android:id="@+id/usernameLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="20dp"
-            android:importantForAutofill="no"
-            android:text="@string/username_label" />
-
-        <EditText
-            android:id="@+id/usernameField"
-            android:layout_width="200sp"
-            android:layout_height="wrap_content"
-            android:layout_alignBaseline="@+id/usernameLabel"
-            android:layout_toEndOf="@id/usernameLabel"
-            android:autofillHints="username"
-            android:inputType="textPersonName" />
-
-        <TextView
-            android:id="@+id/passwordLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignStart="@+id/usernameLabel"
-            android:layout_below="@+id/usernameLabel"
-            android:layout_marginTop="20dp"
-            android:importantForAutofill="no"
-            android:text="@string/password_label" />
-
-        <EditText
-            android:id="@+id/passwordField"
-            android:layout_width="200sp"
-            android:layout_height="wrap_content"
-            android:layout_alignBaseline="@+id/passwordLabel"
-            android:layout_alignStart="@+id/usernameField"
-            android:autofillHints="password"
-            android:inputType="textPassword" />
-    </RelativeLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
+    <TextView
+        android:id="@+id/usernameLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
-        android:gravity="center"
-        android:orientation="horizontal">
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/usernameField"
+        android:text="@string/username_label"
+        app:layout_constraintEnd_toStartOf="@+id/usernameField"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/standard_login_header" />
 
-        <Button
-            android:id="@+id/clear"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Clear" />
+    <EditText
+        android:id="@+id/usernameField"
+        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:autofillHints="username"
+        android:inputType="text"
+        app:layout_constraintBottom_toBottomOf="@+id/usernameLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/usernameLabel"
+        app:layout_constraintTop_toTopOf="@+id/usernameLabel" />
 
-        <Button
-            android:id="@+id/login"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Login" />
-    </LinearLayout>
+    <TextView
+        android:id="@+id/passwordLabel"
+        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/passwordField"
+        android:text="@string/password_label"
+        app:layout_constraintEnd_toStartOf="@+id/passwordField"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/usernameLabel" />
 
-</LinearLayout>
\ No newline at end of file
+    <EditText
+        android:id="@+id/passwordField"
+        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:autofillHints="password"
+        android:inputType="textPassword"
+        app:layout_constraintBottom_toBottomOf="@+id/passwordLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/passwordLabel"
+        app:layout_constraintTop_toTopOf="@+id/passwordLabel" />
+
+    <TextView
+        android:id="@+id/clear"
+        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/clear_label"
+        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/passwordField" />
+
+    <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/clear"
+        app:layout_constraintTop_toTopOf="@+id/clear" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_webview_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_webview_activity.xml
new file mode 100644
index 0000000..3985f72
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_webview_activity.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_with_autocomplete_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_with_autocomplete_activity.xml
new file mode 100644
index 0000000..23375da
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/login_with_autocomplete_activity.xml
@@ -0,0 +1,141 @@
+<?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"
+    android:id="@+id/authLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    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">
+
+    <TextView
+        android:id="@+id/standard_login_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_autocomplete_login_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/autocomplete_login_info"
+        app:layout_constraintBottom_toBottomOf="@+id/standard_login_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/standard_login_header"
+        app:layout_constraintTop_toTopOf="@+id/standard_login_header" />
+
+    <TextView
+        android:id="@+id/usernameLabel"
+        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/usernameField"
+        android:text="@string/username_label"
+        app:layout_constraintEnd_toStartOf="@+id/usernameField"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/standard_login_header" />
+
+    <AutoCompleteTextView
+        android:id="@+id/usernameField"
+        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:autofillHints="username"
+        android:inputType="text"
+        app:layout_constraintBottom_toBottomOf="@+id/usernameLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/usernameLabel"
+        app:layout_constraintTop_toTopOf="@+id/usernameLabel" />
+
+    <TextView
+        android:id="@+id/passwordLabel"
+        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/passwordField"
+        android:text="@string/password_label"
+        app:layout_constraintEnd_toStartOf="@+id/passwordField"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/usernameLabel" />
+
+    <AutoCompleteTextView
+        android:id="@+id/passwordField"
+        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:autofillHints="password"
+        android:inputType="textPassword"
+        app:layout_constraintBottom_toBottomOf="@+id/passwordLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/passwordLabel"
+        app:layout_constraintTop_toTopOf="@+id/passwordLabel" />
+
+    <TextView
+        android:id="@+id/clear"
+        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/passwordField" />
+
+    <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/clear"
+        app:layout_constraintTop_toTopOf="@+id/clear" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_auth_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_auth_activity.xml
new file mode 100644
index 0000000..34b4424
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_auth_activity.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.
+-->
+<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/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_list_item.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_list_item.xml
new file mode 100644
index 0000000..ef56428
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_list_item.xml
@@ -0,0 +1,40 @@
+<?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/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/settings_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml
similarity index 81%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/settings_activity.xml
rename to prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml
index 3704e40..1618bdc 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/settings_activity.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml
@@ -18,21 +18,23 @@
     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"
-    android:importantForAutofill="no">
+    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"/>
+            android:text="@string/settings_authentication_header" />
 
         <LinearLayout
             android:id="@+id/settings_auth_responses_container"
@@ -54,8 +56,8 @@
                 style="@style/Settings.Switch"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:minHeight="@dimen/a11y_min_touch_target_dimen"
-                android:layout_marginStart="@dimen/padding_normal" />
+                android:layout_marginStart="@dimen/padding_normal"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen" />
 
         </LinearLayout>
 
@@ -79,8 +81,8 @@
                 style="@style/Settings.Switch"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:minHeight="@dimen/a11y_min_touch_target_dimen"
-                android:layout_marginStart="@dimen/padding_normal" />
+                android:layout_marginStart="@dimen/padding_normal"
+                android:minHeight="@dimen/a11y_min_touch_target_dimen" />
 
         </LinearLayout>
 
@@ -103,9 +105,9 @@
                 style="@style/Settings.Switch"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:minHeight="@dimen/a11y_min_touch_target_dimen"
                 android:layout_marginStart="@dimen/padding_normal"
-                android:src="@drawable/ic_person_black_24dp"/>
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:src="@drawable/ic_person_black_24dp" />
         </LinearLayout>
 
         <TextView
@@ -113,7 +115,31 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:paddingTop="@dimen/spacing_normal"
-            android:text="@string/settings_data_header"/>
+            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"
@@ -134,9 +160,9 @@
                 style="@style/Settings.Switch"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:minHeight="@dimen/a11y_min_touch_target_dimen"
                 android:layout_marginStart="@dimen/padding_normal"
-                android:src="@drawable/ic_delete_forever_black_24dp"/>
+                android:minHeight="@dimen/a11y_min_touch_target_dimen"
+                android:src="@drawable/ic_delete_forever_black_24dp" />
         </LinearLayout>
     </LinearLayout>
 
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml
similarity index 68%
copy from prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml
copy to prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml
index bc026e5..019a367 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml
@@ -14,11 +14,10 @@
  * 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
+<NumberPicker
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:settingsActivity="com.example.android.autofillframework.service.SettingsActivity"/>
\ No newline at end of file
+    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/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml
similarity index 69%
copy from prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml
copy to prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml
index bc026e5..bfd6931 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml
@@ -14,11 +14,14 @@
  * 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
+<EditText
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:settingsActivity="com.example.android.autofillframework.service.SettingsActivity"/>
\ No newline at end of file
+    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/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml
new file mode 100644
index 0000000..9f6f151
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml
@@ -0,0 +1,95 @@
+<?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"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin">
+
+    <TextView
+        android:id="@+id/multiple_partitions_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_multiple_partitions_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/multiple_partitions"
+        app:layout_constraintBottom_toBottomOf="@+id/multiple_partitions_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/multiple_partitions_header"
+        app:layout_constraintTop_toTopOf="@+id/multiple_partitions_header" />
+
+    <com.example.android.autofillframework.app.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"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/multiple_partitions_header"
+        app:internalTextSize="34sp"/>
+
+    <TextView
+        android:id="@+id/clear"
+        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_large"
+        android:text="@string/clear_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toStartOf="@+id/submit"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/custom_view" />
+
+    <TextView
+        android:id="@+id/submit"
+        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/submit_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/clear"
+        app:layout_constraintTop_toTopOf="@+id/clear" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/navigation_button.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/navigation_button.xml
new file mode 100644
index 0000000..e4c91ec
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/navigation_button.xml
@@ -0,0 +1,45 @@
+<?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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:tools="http://schemas.android.com/tools">
+
+    <LinearLayout
+        android:id="@+id/navigation_button_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <ImageButton
+            android:id="@+id/infoButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
+            android:layout_marginVertical="@dimen/activity_vertical_margin"
+            android:background="@drawable/ic_info_black_24dp" />
+
+        <TextView
+            android:id="@+id/buttonLabel"
+            style="@style/TextAppearance.AppCompat.Medium"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
+            android:layout_marginVertical="@dimen/activity_vertical_margin"
+            android:minLines="2"
+            tools:text="@string/navigation_button_edittext_login_label" />
+    </LinearLayout>
+</merge>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/navigation_item.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/navigation_item.xml
new file mode 100644
index 0000000..9c7b3c7
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/navigation_item.xml
@@ -0,0 +1,67 @@
+<?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.
+-->
+<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">
+
+    <android.support.constraint.ConstraintLayout
+        android:id="@+id/navigation_item_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginVertical="@dimen/spacing_micro">
+
+        <android.support.v7.widget.CardView
+            android:id="@+id/cardView"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="8dp"
+            android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
+            android:layout_marginVertical="@dimen/spacing_micro"
+            android:clickable="true"
+            android:foreground="?android:attr/selectableItemBackground"
+            app:cardCornerRadius="@dimen/spacing_micro"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/infoButton"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent">
+
+            <TextView
+                android:id="@+id/buttonLabel"
+                style="@style/TextAppearance.AppCompat.Medium"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:drawablePadding="@dimen/spacing_normal"
+                android:minLines="2"
+                android:paddingHorizontal="@dimen/padding_normal"
+                android:paddingVertical="@dimen/padding_normal"
+                tools:text="@string/navigation_button_edittext_login_label" />
+        </android.support.v7.widget.CardView>
+
+        <com.example.android.autofillframework.app.InfoButton
+            android:id="@+id/infoButton"
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_gravity="center"
+            android:layout_marginHorizontal="@dimen/spacing_normal"
+            android:background="@android:color/transparent"
+            android:src="@drawable/ic_info_black_24dp"
+            app:dialogText=""
+            app:layout_constraintBottom_toBottomOf="@+id/cardView"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/cardView" />
+    </android.support.constraint.ConstraintLayout>
+</merge>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/settings_authentication_dialog.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/settings_authentication_dialog.xml
deleted file mode 100644
index 93ac6dd..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/settings_authentication_dialog.xml
+++ /dev/null
@@ -1,26 +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/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/virtual_login_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/virtual_login_activity.xml
index 59f56e1..af52fb6 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/virtual_login_activity.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/virtual_login_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,35 +13,81 @@
  * 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:weightSum="100">
+<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"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin">
+
+    <TextView
+        android:id="@+id/custom_virtual_login_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_custom_virtual_view_login_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/custom_virtual_login_info"
+        app:layout_constraintBottom_toBottomOf="@+id/custom_virtual_login_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/custom_virtual_login_header"
+        app:layout_constraintTop_toTopOf="@+id/custom_virtual_login_header" />
 
     <com.example.android.autofillframework.app.CustomVirtualView
         android:id="@+id/custom_view"
         android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="50" />
+        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"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/custom_virtual_login_header" />
 
-    <LinearLayout
-        android:layout_width="match_parent"
+    <TextView
+        android:id="@+id/clear"
+        style="@style/Widget.AppCompat.Button.Borderless"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
-        android:gravity="center"
-        android:orientation="horizontal">
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:text="@string/clear_label"
+        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/custom_view" />
 
-        <Button
-            android:id="@+id/clear"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Clear" />
-
-        <Button
-            android:id="@+id/login"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Login" />
-    </LinearLayout>
-</LinearLayout>
+    <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/clear"
+        app:layout_constraintTop_toTopOf="@+id/clear" />
+</android.support.constraint.ConstraintLayout>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/welcome_activity.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/welcome_activity.xml
index 4d746c5..60d6e1f 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/welcome_activity.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/layout/welcome_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,17 +13,26 @@
  * 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="wrap_content"
-             android:layout_height="match_parent"
-             android:paddingBottom="@dimen/activity_vertical_margin"
-             android:paddingLeft="@dimen/activity_horizontal_margin"
-             android:paddingRight="@dimen/activity_horizontal_margin"
-             android:paddingTop="@dimen/activity_vertical_margin">
+<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/activity_vertical_margin"
+    android:paddingTop="@dimen/activity_vertical_margin">
 
     <TextView
-        android:layout_width="match_parent"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
         android:text="@string/welcome_text" />
-</FrameLayout>
\ No newline at end of file
+
+    <TextView
+        android:id="@+id/countdownText"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/spacing_large" />
+</LinearLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/raw/sample_form.html b/prebuilts/gradle/AutofillFramework/Application/src/main/res/raw/sample_form.html
new file mode 100644
index 0000000..2a26223
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/raw/sample_form.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!--
+ * 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.
+-->
+<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>
+</html>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-sw600dp/template-styles.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-sw600dp/template-styles.xml
deleted file mode 100644
index 03d1974..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-sw600dp/template-styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-  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/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-v11/template-styles.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-v11/template-styles.xml
deleted file mode 100644
index 8c1ea66..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-v11/template-styles.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-  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/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-v21/base-colors.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-v21/base-colors.xml
deleted file mode 100644
index 8b6ec3f..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-v21/base-colors.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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>
-
-
-</resources>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-v21/base-template-styles.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-v21/base-template-styles.xml
deleted file mode 100644
index c778e4f..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-v21/base-template-styles.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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">
-    </style>
-
-</resources>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/attrs.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..23bf5cf
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/attrs.xml
@@ -0,0 +1,30 @@
+<?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>
+    <declare-styleable name="NavigationItem">
+        <attr name="labelText" format="string" />
+        <attr name="infoText" format="string" />
+        <attr name="itemLogo" format="integer" />
+        <attr name="imageColor" format="reference" />
+    </declare-styleable>
+    <declare-styleable name="InfoButton">
+        <attr name="dialogText" format="string" />
+    </declare-styleable>
+    <declare-styleable name="CustomVirtualView">
+        <attr name="internalTextSize" format="dimension" />
+    </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/base-strings.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/base-strings.xml
deleted file mode 100644
index ddf8b07..0000000
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/base-strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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">AutofillFramework</string>
-    <string name="intro_message">
-        <![CDATA[
-        
-            
-            This sample app demos the Autofill feature introduced in Android O.
-            
-        
-        ]]>
-    </string>
-</resources>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/dimens.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/dimens.xml
index 961725d..43410b8 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/dimens.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/dimens.xml
@@ -25,4 +25,7 @@
     <dimen name="padding_normal_button">12dp</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="custom_view_height">150dp</dimen>
+    <dimen name="multiple_partitions_height">450dp</dimen>
 </resources>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/strings.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/strings.xml
index b5611ae..01a743b 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/strings.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/strings.xml
@@ -16,27 +16,52 @@
 -->
 
 <resources>
+    <string name="app_name">Autofill Sample</string>
     <string name="settings_name">Autofill Settings</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>
+    <string name="navigation_button_edittext_login_label">Sample Login Using EditTexts</string>
+    <string name="navigation_button_autocomplete_login_label">Sample Login Using AutoCompleteTextViews</string>
+    <string name="navigation_button_email_compose_label">Sample Email Compose Using EditTexts</string>
+    <string name="navigation_button_compound_view_credit_card_label">Sample Credit Card Check Out Using Compound Views</string>
+    <string name="navigation_button_date_picker_credit_card_label">Sample Credit Card Check Out Using Date Picker</string>
+    <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="username_label">Username</string>
     <string name="password_label">Password</string>
-    <string name="welcome_text">You have successfully signed in!</string>
+    <string name="welcome_text">Success!</string>
     <string name="standard_view_sign_in">Sign in using standard views</string>
-    <string name="virtual_view_sign_in">Sign in using virtual views</string>
-    <string name="credit_card_checkout">Credit Card check out</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 Exp</string>
+    <string name="credit_card_expiration_label">CC Expiration</string>
+    <string name="credit_card_expiration_date_label">CC Exp Date</string>
+    <string name="credit_card_expiration_day_label">CC Exp Day</string>
+    <string name="credit_card_expiration_month_label">CC Exp Month</string>
+    <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_clear_data_label">Clear all data (including credentials)</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>
@@ -44,19 +69,109 @@
     <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.
+    </string>
+    <string name="autocomplete_login_info">This is a sample login page that uses
+        AutoCompleteTextViews instead of EditTexts. The AutoComplete dialogs can potentially
+        interfere with the Autofill dialogs, so it is necessary to implement the AutofillCallback to
+        disable AutoComplete when Autofill is working.
+    </string>
+    <string name="custom_virtual_login_info">This is a sample login page that uses a custom View
+        with virtual children. Since the Autofill framework does not know how to autofill the
+        virtual children out of the box, it is necessary implement certain Autofill-specific methods
+        and interface directly with AutofillManager.
+    </string>
+    <string name="credit_card_info">This is a sample credit card checkout page that uses
+        EditTexts to input data into the form.
+    </string>
+    <string name="spinners_credit_card_info">This is a sample credit card checkout page that uses
+        EditTexts and Spinners to input data into the form. While EditTexts are optimized out of the
+        box, Spinners can require a small amount of work when using a custom array adapter.
+        In that case, you need to tell the Autofill framework which values in the adapter map to
+        which indices.
+    </string>
+    <string name="email_compose_info">
+        This is a sample email compose page that uses EditTexts to compose the email. Since none of
+        the fields on the page are important to autofill, it is necessary to set the
+        android:importantForAutofill XML property appropriately for each View. You can either set it
+        to &quot;no&quot; on all non-autofillable Views, or set &quot;noExcludeDescendants&quot;
+        on the root View if all Views in the hierarchy should not be autofilled. In this case, we
+        did the latter.
+    </string>
+    <string name="compound_view_credit_card_info">
+        This is a sample credit card checkout page that uses a custom compound View to input the
+        credit card\'s expiration date and an EditText to input the credit card number. While the
+        EditText is optimized out of the box for autofill, this example shows how to implement
+        certain Autofill-specific methods and XML properties for the custom compound view.
+    </string>
+    <string name="webview_login_info">
+        This is a sample login page that uses a WebView to control the UI. The HTML on the web page
+        uses standard W3C autofill hints that the autofill service recognizes. No extra code is
+        needed other than these hints.
+    </string>
+    <string name="date_picker_credit_card_info">
+        This is a sample credit card checkout page that uses a custom EditText and a DatePicker
+        to input the credit card\'s expiration date and an EditText to input the credit card number.
+        While the EditText is optimized out of the box for autofill, this example shows how to
+        use it to autofill a date field.
+    </string>
+    <string name="multiple_partitions">
+        This is a sample page that contains multiple partitions (login credentials, address,
+        credit card info) and can be used to make sure that only one partition can be autofilled
+        at time.
+    </string>
+    <string name="anti_pattern_credit_card_info">This is a sample credit card checkout page that
+        uses a standard EditText fields to represent the full credit card expiration date (which
+        is tagged with the View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE hint).
+        This is an anti-pattern because its autofill type is View.AUTOFILL_TYPE_TEXT,
+        which makes it harder for the autofill service to figure out how to fill them.
+        For example, should a month/year date be represent as "04/2020", "4/2020" or "4/20"?
+        Or perhaps the year comes first, so it could be "2020/04", "2020/4" or "20/4"?
+        The proper way to represent a View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE field
+        is through a View.AUTOFILL_TYPE_DATE value, which is what the other credit card sample
+        activities use.
+    </string>
+
+    <string name="partition_credentials">Credentials</string>
+    <string name="partition_credit_card">Credit Card</string>
+
+    <string name="message_autofill_ok">Autofilled partition \'%1$s\'</string>
+    <string name="message_autofill_no_partitions">No partition for id %1$d on %2$s</string>
+    <string name="message_autofill_blocked">Blocked cross-partitions: %1$s</string>
+    <string name="message_autofill_readonly">Ignoring autofill on read-only field %1$s</string>
+    <string name="message_autofill_invalid">INVALID</string>
+    <string name="message_credit_card_expiration_type">Representing expiration dates as %1$s</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="month_array">
-        <item>Jan</item>
-        <item>Feb</item>
-        <item>Mar</item>
-        <item>Apr</item>
-        <item>May</item>
-        <item>Jun</item>
-        <item>Jul</item>
-        <item>Aug</item>
-        <item>Sep</item>
-        <item>Oct</item>
-        <item>Nov</item>
-        <item>Dec</item>
+        <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">
@@ -87,20 +202,11 @@
         <item>25</item>
         <item>26</item>
         <item>27</item>
-        <item>28</item>
-        <item>30</item>
-        <item>31</item>
     </string-array>
 
-    <string-array name="year_array">
-        <item>2017</item>
-        <item>2018</item>
-        <item>2019</item>
-        <item>2020</item>
-        <item>2021</item>
-        <item>2022</item>
-        <item>2023</item>
-        <item>2024</item>
+    <string-array name="mock_autocomplete_sign_in_suggestions">
+        <item>user-1</item>
+        <item>user-2</item>
     </string-array>
 
 </resources>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/styles.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/styles.xml
index 92aabaa..c44f999 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/styles.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/styles.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,12 +14,14 @@
  * limitations under the License.
 -->
 <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>
@@ -29,6 +30,7 @@
         <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>
@@ -39,4 +41,12 @@
         <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>
+
+    <style name="MyDatePickerStyle" parent="@android:style/Widget.Material.DatePicker">
+        <item name="android:datePickerMode">spinner</item>
+    </style>
 </resources>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml b/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/multidataset_service.xml
similarity index 94%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml
rename to prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/multidataset_service.xml
index bc026e5..0c1c14d 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml
+++ b/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/multidataset_service.xml
@@ -21,4 +21,4 @@
 -->
 <autofill-service
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:settingsActivity="com.example.android.autofillframework.service.SettingsActivity"/>
\ No newline at end of file
+    android:settingsActivity="com.example.android.autofillframework.multidatasetservice.settings.SettingsActivity"/>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/NOTICE b/prebuilts/gradle/AutofillFramework/NOTICE
new file mode 100644
index 0000000..8f8105a
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/NOTICE
@@ -0,0 +1,16 @@
+
+This sample uses the following software:
+
+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.
diff --git a/prebuilts/gradle/AutofillFramework/README.md b/prebuilts/gradle/AutofillFramework/README.md
index d1feafb..0b19827 100644
--- a/prebuilts/gradle/AutofillFramework/README.md
+++ b/prebuilts/gradle/AutofillFramework/README.md
@@ -3,62 +3,95 @@
 ===================================
 
 This sample demonstrates the use of the Autofill Framework. It includes implementations of client
-Activities that want to be autofilled, and a Service that can provide autofill data to client
-Activities. For simplicity, this sample's service uses mock data to autofill what it thinks are
-username and password text fields.
+Activities with views that should be autofilled, and a Service that can provide autofill data to
+client Activities.
 
 Introduction
 ------------
 
 This sample demonstrates the use of the Autofill framework from the service side and the client
-side. In practice, only a small handful of apps will develop Autofill services because a device will
-only have one service as default at a time. However, all apps targeting O with any autofillable
-fields should follow the necessary steps to ensure their Views can be autofilled. Most of the time,
-there is little to no extra code involved, but the use of custom views and views with virtual child
-views requires more work.
+side. In practice, only a small handful of apps will develop Autofill services because a device
+will only have one service as default at a time, and there is just a small number of 3rd-party apps
+providing these services (typically password managers). However, all apps targeting O with any
+autofillable fields should follow the necessary steps to 1) ensure their views can be autofilled
+and 2) optimize their autofill performance. Most of the time, there is little to no extra code
+involved, but the use of custom views and views with virtual child views requires more work.
 
-The sample's Autofill service is implemented to parse the client's view hierarchy in search of text
-fields that it has data for. If such text fields exist in the hierarchy, the service sends data
-suggestions to the client to fill in those text fields. In this basic sample, it will only look for
-views whose resource IDs are "usernameField" and "passwordField" and will send mock credential data
-accordingly. A real Autofill service would attempt to autofill more than just login credentials and
-would be able to fill in other view types in addition to text fields (e.g. spinners, checkboxes,
-etc.). It would also use more advanced heuristics to determine what data to send to which views.
+The sample's Autofill service is implemented to parse the client's view hierarchy in search of
+autofillable fields that it has data for. If such fields exist in the hierarchy, the service sends
+data suggestions to the client to autofill those fields. The client uses the following attributes
+to specify autofill properties: `importantForAutofill`, `autofillHints`, and `autofillType`.
+`importantForAutofill` specifies whether the view is autofillable. `autofillHints` is a list of
+strings that hint to the service **what** data to fill the view with. This sample service only
+supports the hints listed [here](https://developer.android.com/reference/android/view/View.html#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE)
+with the prefix AUTOFILL_HINT_*. `autofillType` tells the service the type of data it expects to
+receive (i.e. a list index, a date, or a string). Specifying `autofillType` is only necessary
+when implementing a custom view since all of the provided widgets in the UI toolkit do this for you.
 
-To set the device's default Autofill service to the one in the sample, edit
-**Settings** > **Apps &amp; Notifications** > **Default Apps** > **Auto-fill app** and select the
-sample app. To edit the service's settings, open the **Autofill Settings** launcher icon. Here, you
-can set whether you want to enable authentication on the entire Autofill Response or just on
-individual datasets. You can also set the number of mock datasets that are sent to the client app.
+To set the device's default Autofill service to the one in the sample, edit **Settings** >
+**System** > **Languages &amp; Input** > **Advanced** > **Auto-fill service** and select the sample
+app. To edit the service's settings, tap the settings icon next to the **Auto-fill service** list
+item or open the **Autofill Settings** launcher icon.. Here, you can set whether you want to enable
+authentication on the entire autofill Response or just on individual autofill datasets. You should
+also set the master password to “unlock” authenticated autofill data with.
 
-The client side of the app has two Activities that each have a username field and a password field.
-One of the Activities uses standard views and the other Activity uses a custom view with virtual
-children. The standard views do not require any extra code to allow autofill. The following code
-example shows the `View` method you have to override in order to provide view hierarchy data to the
-Autofill service. This is triggered when the `View` goes into focus and Android invokes an Autofill
-request.
+**Note:** This sample service stores all autofill data in SharedPreferences and thus is not secure.
+Be careful about what you store when experimenting with the sample because anyone with root access
+to your device will be able to view your autofill data.
+
+The client side of the app has three Activities that each have autofillable fields. The first
+Activity uses standard views to comprise a login form. Very little needs to be done by the client
+app to ensure the views get autofilled properly. The second Activity uses a custom view with
+virtual children, meaning some autofillable child views are not known to the View hierarchy to be
+child views. Supporting autofill on these child views is a little more involved.
+
+The following code snippet shows how to signal to the autofill service that a specific
+autofillable virtual view has come into focus:
 
 ```java
-/*
-This method is responsible for building the ViewStructure that gets passed to the AutoFillService
-by the framework when it is time to find Autofill suggestions. To do this, it should traverse
-through its view hierarchy and add views to the ViewStructure on the way.
-*/
+class CustomVirtualView {
+...
+    // Cache AutofillManager system service
+    mAutofillManager = context.getSystemService(AutofillManager.class);
+...
+    // Notify service which virtual view has come into focus.
+    mAutofillManager.notifyViewEntered(CustomVirtualView.this, id, absBounds);
+...
+   // Notify service that a virtual view has left focus.
+   mAutofillManager.notifyViewExited(CustomVirtualView.this, id);
+}
+```
+
+Now that the autofillable view has signaled to the service that it has been autofilled, it needs
+to provide the virtual view hierarchy to the Autofill service. This is done out of the box for
+views part of the UI toolkit, but you need to implement this yourself if you have the view has
+virtual child views. The following code example shows the `View` method you have to override in
+order to provide this view hierarchy data to the Autofill service.
+
+```java
 @Override
-public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
-  structure.setClassName(getClass().getName());
-  int childrenSize = mItems.size();
-  int index = structure.addChildCount(childrenSize);
-  for (int i = 0; i < childrenSize; i++) {
-      Item item = mItems.valueAt(i);
-      ViewStructure child = structure.newChild(index, item.id, flags);
-      child.setSanitized(item.sanitized);
-      child.setText(item.text);
-      child.setAutoFillValue(AutoFillValue.forText(item.text));
-      child.setFocused(item.line.focused);
-      child.setId(item.id, getContext().getPackageName(), null, item.line.idEntry);
-      index++;
-  }
+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 = mItems.size();
+    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 = mItems.valueAt(i);
+        ViewStructure child = structure.newChild(index);
+        child.setAutofillId(structure, item.id);
+        child.setAutofillHints(item.hints);
+        child.setAutofillType(item.type);
+        child.setDataIsSensitive(!item.sanitized);
+        child.setText(item.text);
+        child.setAutofillValue(AutofillValue.forText(item.text));
+        child.setFocused(item.focused);
+        child.setId(item.id, getContext().getPackageName(), null, item.line.idEntry);
+        child.setClassName(item.getClassName());
+        index++;
+    }
 }
 ```
 
@@ -66,44 +99,45 @@
 (wrapped in a `Response` object), the user can pick which `Dataset` they want to autofill their
 views with. When a `Dataset` is selected, this method is invoked for all of the views that were
 associated with that `Dataset` by the service. For example, the `Dataset` might contain Autofill
-values for username, password, birthday, and address. This method would then be invoked on all four
-of those fields. The following code example shows how the sample app implements the method to
-deliver a UI update to the appropriate child view after the user makes their selection.
+values for username, password, birthday, and address. This method would then be invoked on all
+four of those fields. The following code example shows how the sample app implements the method
+to deliver a UI update to the appropriate child view after the user makes their selection.
 
 ```java
-/*
-User has just selected a Dataset from the list of Autofill suggestions and the Dataset's
-AutoFillValue gets passed into this method. This method updates the UI based on the data
-in the AutoFillValue.
-*/
 @Override
-public void autoFillVirtual(int id, AutoFillValue value) {
-  Item item = mItems.get(id);
-  if (item == null) {
-      // ID not recognized so no-op.
-      return;
-  }
-  if (!item.editable) {
-      // Component is not editable so no-op.
-      return;
-  }
-  // Set the virtual child view's text to the text wrapped in the AutoFillValue.
-  item.text = value.getTextValue();
-  postInvalidate();
+public void autofill(SparseArray<AutofillValue> values) {
+    // 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.
+    for (int i = 0; i < values.size(); i++) {
+        final int id = values.keyAt(i);
+        final AutofillValue value = values.valueAt(i);
+        final Item item = mItems.get(id);
+        if (item != null && item.editable) {
+            // Set the item's text to the text wrapped in the AutofillValue.
+            item.text = value.getTextValue();
+        } else if (item == null) {
+            // Component not found, so no-op.
+        } else {
+            // Component not editable, so no-op.
+        }
+    }
+    postInvalidate();
 }
 ```
 
 Pre-requisites
 --------------
 
-- Android SDK Preview O
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
 -------------
 
-<img src="screenshots/1_HomePage.png" height="400" alt="Screenshot"/> <img src="screenshots/2_StandardViewAutofillable.png" height="400" alt="Screenshot"/> <img src="screenshots/3_StandardViewAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/4_WelcomeActivity.png" height="400" alt="Screenshot"/> <img src="screenshots/5_CustomViewAutofillable.png" height="400" alt="Screenshot"/> <img src="screenshots/6_CustomViewAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/7_SettingsActivity.png" height="400" alt="Screenshot"/> <img src="screenshots/8_AuthNeeded.png" height="400" alt="Screenshot"/> <img src="screenshots/9_AuthActivity.png" height="400" alt="Screenshot"/> 
+<img src="screenshots/1_MainPage.png" height="400" alt="Screenshot"/> <img src="screenshots/2_SampleLoginEditTexts.png" height="400" alt="Screenshot"/> <img src="screenshots/3_SampleLoginEditTextsAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/4_WelcomeActivity.png" height="400" alt="Screenshot"/> <img src="screenshots/5_SampleLoginCustomVirtualView.png" height="400" alt="Screenshot"/> <img src="screenshots/6_SampleLoginCustomVirtualViewAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/7_SampleCheckOutSpinnersAutofillable.png" height="400" alt="Screenshot"/> <img src="screenshots/8_SampleCheckOutSpinnersAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/9_SettingsActivity.png" height="400" alt="Screenshot"/> <img src="screenshots/10_AuthNeeded.png" height="400" alt="Screenshot"/> <img src="screenshots/11_AuthActivity.png" height="400" alt="Screenshot"/> 
 
 Getting Started
 ---------------
diff --git a/prebuilts/gradle/AutofillFramework/build.gradle b/prebuilts/gradle/AutofillFramework/build.gradle
index 1901ba9..d00ad15 100644
--- a/prebuilts/gradle/AutofillFramework/build.gradle
+++ b/prebuilts/gradle/AutofillFramework/build.gradle
@@ -1,4 +1,24 @@
+// 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'
+    }
+  }
+  dependencies {
+    classpath 'com.android.tools.build:gradle:2.3.3'
+  }
+}
 
+allprojects {
+  repositories {
+    jcenter()
+    maven {
+      url 'https://maven.google.com'
+    }
+  }
+}
 
 
 
diff --git a/prebuilts/gradle/AutofillFramework/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/AutofillFramework/gradle/wrapper/gradle-wrapper.properties
index 3907cb5..6342626 100644
--- a/prebuilts/gradle/AutofillFramework/gradle/wrapper/gradle-wrapper.properties
+++ b/prebuilts/gradle/AutofillFramework/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Apr 10 15:27:10 PDT 2013
+#Fri Jul 28 14:29:44 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.1-milestone-1-all.zip
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/build.gradle b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/build.gradle
index fb5adcc..ed1d6a2 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/build.gradle
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/build.gradle
@@ -1,27 +1,15 @@
-
-buildscript {
-    repositories {
-        jcenter()
-    }
-    ext.kotlin_version = '1.1.2-4'
-    dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
-        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
-    }
-}
-
 apply plugin: 'com.android.application'
 apply plugin: 'kotlin-android'
-
-repositories {
-    jcenter()
-}
+apply plugin: 'kotlin-android-extensions'
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.0.1"
+    compile "com.android.support:support-v13:26.0.1"
+    compile 'com.android.support:appcompat-v7:26.0.1'
+    compile 'com.android.support:cardview-v7:26.0.1'
+    compile 'com.android.support:design:26.0.1'
+    compile 'com.android.support.constraint:constraint-layout:1.0.2'
+    compile 'com.google.code.gson:gson:2.8.1'
     compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
 }
 
@@ -29,17 +17,15 @@
 // 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
+        'main']     // main sample code; look here for the interesting stuff.
 
 android {
-    compileSdkVersion "android-O"
-    buildToolsVersion "25.0.2"
+    compileSdkVersion 26
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
-        minSdkVersion "O"
-        targetSdkVersion "O"
+        minSdkVersion 26
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml
index 28d9c0b..2470645 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
+<?xml version="1.0" encoding="UTF-8"?><!--
  Copyright 2017 The Android Open Source Project
 
  Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +15,9 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.example.android.autofillframework"
-          android:versionCode="1"
-          android:versionName="1.0">
+    package="com.example.android.autofillframework"
+    android:versionCode="1"
+    android:versionName="1.0">
 
     <application
         android:allowBackup="true"
@@ -28,57 +27,42 @@
         android:theme="@style/Theme.AppCompat.Light">
         <activity
             android:name=".app.MainActivity"
-            android:label="AF Main"
             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=".app.LoginActivity"
-            android:label="AF StandardLogin"
-            android:taskAffinity=".LoginActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
+            android:name=".app.StandardSignInActivity"
+            android:taskAffinity=".StandardSignInActivity" />
         <activity
-            android:name=".app.VirtualLoginActivity"
-            android:label="AF VirtualLogin"
-            android:taskAffinity=".VirtualLoginActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </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:label="AF CreditCard"
-            android:taskAffinity=".CreditCardActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
+            android:taskAffinity=".CreditCardActivity" />
+        <activity
+            android:name=".app.EmailComposeActivity"
+            android:taskAffinity=".EmailComposeActivity" />
+        <activity
+            android:name=".app.CreditCardCompoundViewActivity"
+            android:taskAffinity=".CreditCardCompoundViewActivity" />
         <!--
         Including launcher icon for Autofill Settings to convenience.
         Not necessary for a real service.
         -->
         <activity
-            android:name=".service.settings.SettingsActivity"
+            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" />
-
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
@@ -89,19 +73,19 @@
         Settings Activity based on what the meta-data resource points to.
         -->
         <service
-            android:name=".service.MyAutofillService"
-            android:permission="android.permission.BIND_AUTOFILL"
-            android:label="Sample Autofill Service">
+            android:name=".multidatasetservice.MyAutofillService"
+            android:label="Multi-Dataset Autofill Service"
+            android:permission="android.permission.BIND_AUTOFILL">
             <meta-data
                 android:name="android.autofill"
-                android:resource="@xml/autofill_service" />
+                android:resource="@xml/multidataset_service" />
 
             <intent-filter>
                 <action android:name="android.service.autofill.AutofillService" />
             </intent-filter>
         </service>
 
-        <activity android:name=".service.AuthActivity" />
+        <activity android:name=".multidatasetservice.AuthActivity" />
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java
deleted file mode 100644
index 5404990..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.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;
-
-import android.os.Bundle;
-
-import java.util.Arrays;
-import java.util.Set;
-
-public final class CommonUtil {
-
-    public static final String TAG = "AutofillSample";
-
-    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();
-    }
-}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.kt
new file mode 100644
index 0000000..c64a670
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.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.autofillframework
+
+import android.os.Bundle
+import com.google.gson.Gson
+import com.google.gson.GsonBuilder
+import java.util.Arrays
+
+object CommonUtil {
+
+    val TAG = "AutofillSample"
+
+    val EXTRA_DATASET_NAME = "dataset_name"
+    val EXTRA_FOR_RESPONSE = "for_response"
+
+    private fun bundleToString(builder: StringBuilder, data: Bundle) {
+        val keySet = data.keySet()
+        builder.append("[Bundle with ").append(keySet.size).append(" keys:")
+        for (key in keySet) {
+            builder.append(' ').append(key).append('=')
+            val value = data.get(key)
+            if (value is Bundle) {
+                bundleToString(builder, value)
+            } else {
+                val string = if (value is Array<*>) Arrays.toString(value) else value
+                builder.append(string)
+            }
+        }
+        builder.append(']')
+    }
+
+    fun bundleToString(data: Bundle?): String {
+        if (data == null) {
+            return "N/A"
+        }
+        val builder = StringBuilder()
+        bundleToString(builder, data)
+        return builder.toString()
+    }
+
+    fun createGson(): Gson {
+        return GsonBuilder().excludeFieldsWithoutExposeAnnotation().setPrettyPrinting().create()
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.kt
index f2d9a8b..8000d91 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.kt
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.kt
@@ -19,70 +19,69 @@
 import android.content.Intent
 import android.os.Bundle
 import android.support.v7.app.AppCompatActivity
-import android.view.View
 import android.widget.ArrayAdapter
-import android.widget.Button
-import android.widget.Spinner
-
 import com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.credit_card_activity.clear
+import kotlinx.android.synthetic.main.credit_card_activity.creditCardNumberField
+import kotlinx.android.synthetic.main.credit_card_activity.expirationDay
+import kotlinx.android.synthetic.main.credit_card_activity.expirationMonth
+import kotlinx.android.synthetic.main.credit_card_activity.expirationYear
+import kotlinx.android.synthetic.main.credit_card_activity.submit
+import java.util.Calendar
+
 
 class CreditCardActivity : AppCompatActivity() {
 
-    private var mCcExpirationDaySpinner: Spinner? = null
-    private var mCcExpirationMonthSpinner: Spinner? = null
-    private var mCcExpirationYearSpinner: Spinner? = null
-    private var mSubmitButton: Button? = null
-    private var mClearButton: Button? = null
+    private val CC_EXP_YEARS_COUNT = 5
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-
         setContentView(R.layout.credit_card_activity)
 
-        mSubmitButton = findViewById(R.id.submit) as Button
-        mClearButton = findViewById(R.id.clear) as Button
-        mCcExpirationDaySpinner = findViewById(R.id.expirationDay) as Spinner
-        mCcExpirationMonthSpinner = findViewById(R.id.expirationMonth) as Spinner
-        mCcExpirationYearSpinner = findViewById(R.id.expirationYear) as Spinner
-
         // Create an ArrayAdapter using the string array and a default spinner layout
-        val 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!!.adapter = dayAdapter
+        expirationDay.adapter = ArrayAdapter.createFromResource(this, R.array.day_array,
+                android.R.layout.simple_spinner_item).apply {
+            // Specify the layout to use when the list of choices appears
+            setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+        }
 
-        val monthAdapter = ArrayAdapter.createFromResource(this, R.array.month_array, android.R.layout.simple_spinner_item)
-        monthAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
-        mCcExpirationMonthSpinner!!.adapter = monthAdapter
+        expirationMonth.adapter = ArrayAdapter.createFromResource(this, R.array.month_array,
+                android.R.layout.simple_spinner_item).apply {
+            setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+        }
 
-        val yearAdapter = ArrayAdapter.createFromResource(this, R.array.year_array, android.R.layout.simple_spinner_item)
-        yearAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
-        mCcExpirationYearSpinner!!.adapter = yearAdapter
+        val year = Calendar.getInstance().get(Calendar.YEAR)
 
-        mSubmitButton!!.setOnClickListener { submit() }
-        mClearButton!!.setOnClickListener { resetFields() }
+        val years = (0 until CC_EXP_YEARS_COUNT)
+                .map { Integer.toString(year + it) }
+                .toTypedArray<CharSequence>()
+
+        expirationYear.adapter = object : ArrayAdapter<CharSequence?>(this,
+                android.R.layout.simple_spinner_item, years) {
+            override fun getAutofillOptions() = years
+        }
+        submit.setOnClickListener { submitCcInfo() }
+        clear.setOnClickListener { resetFields() }
     }
 
     private fun resetFields() {
-        //TODO
+        creditCardNumberField.setText("")
+        expirationDay.setSelection(0)
+        expirationMonth.setSelection(0)
+        expirationYear.setSelection(0)
     }
 
     /**
      * Launches new Activity and finishes, triggering an autofill save request if the user entered
      * any new data.
      */
-    private fun submit() {
-        val intent = WelcomeActivity.getStartActivityIntent(this@CreditCardActivity)
-        startActivity(intent)
+    private fun submitCcInfo() {
+        startActivity(WelcomeActivity.getStartActivityIntent(this))
         finish()
     }
 
     companion object {
-
-        fun getStartActivityIntent(context: Context): Intent {
-            val intent = Intent(context, CreditCardActivity::class.java)
-            return intent
-        }
+        fun getStartActivityIntent(context: Context) =
+                Intent(context, CreditCardActivity::class.java)
     }
 }
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardCompoundViewActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardCompoundViewActivity.kt
new file mode 100644
index 0000000..d83a7df
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardCompoundViewActivity.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.autofillframework.app
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.credit_card_compound_view_activity.clearButton
+import kotlinx.android.synthetic.main.credit_card_compound_view_activity.creditCardExpirationView
+import kotlinx.android.synthetic.main.credit_card_compound_view_activity.creditCardNumberField
+import kotlinx.android.synthetic.main.credit_card_compound_view_activity.submitButton
+
+class CreditCardCompoundViewActivity : AppCompatActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.credit_card_compound_view_activity)
+        submitButton.setOnClickListener { submit() }
+        clearButton.setOnClickListener { resetFields() }
+    }
+
+    private fun resetFields() {
+        creditCardExpirationView.reset()
+        creditCardNumberField.setText("")
+    }
+
+    /**
+     * Launches new Activity and finishes, triggering an autofill save request if the user entered
+     * any new data.
+     */
+    private fun submit() {
+        val intent = WelcomeActivity.getStartActivityIntent(this)
+        startActivity(intent)
+        finish()
+    }
+
+    companion object {
+        fun getStartActivityIntent(context: Context): Intent {
+            val intent = Intent(context, CreditCardCompoundViewActivity::class.java)
+            return intent
+        }
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDateView.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDateView.kt
new file mode 100644
index 0000000..b361192
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardExpirationDateView.kt
@@ -0,0 +1,108 @@
+/*
+ * 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.util.AttributeSet
+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 com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.cc_exp_date.view.ccExpMonth
+import kotlinx.android.synthetic.main.cc_exp_date.view.ccExpYear
+import java.util.Calendar
+
+class CreditCardExpirationDateView @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyleAttr: Int = 0,
+        defStyleRes: Int = 0
+) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) {
+
+    private val startYear = Calendar.getInstance().get(Calendar.YEAR)
+
+    init {
+        LayoutInflater.from(context).inflate(R.layout.cc_exp_date, this)
+        importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS
+        val spinnerOnItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+            override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int,
+                    id: Long) {
+                context.getSystemService(AutofillManager::class.java)
+                        .notifyValueChanged(this@CreditCardExpirationDateView)
+            }
+
+            override fun onNothingSelected(parent: AdapterView<*>) = Unit
+        }
+        val years = arrayOfNulls<String>(CC_EXP_YEARS_COUNT)
+        for (i in 0 until years.size) {
+            years[i] = Integer.toString(startYear + i)
+        }
+
+        with(ccExpMonth) {
+            adapter = ArrayAdapter.createFromResource(context, R.array.month_array,
+                    android.R.layout.simple_spinner_item).apply {
+                setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+            }
+            onItemSelectedListener = spinnerOnItemSelectedListener
+        }
+
+        with(ccExpYear) {
+            adapter = ArrayAdapter<String>(context,
+                    android.R.layout.simple_spinner_item, years)
+            onItemSelectedListener = spinnerOnItemSelectedListener
+        }
+    }
+
+    override fun getAutofillValue() =
+            AutofillValue.forDate(Calendar.getInstance().apply {
+                // clear() sets hours, minutes, seconds, and millis to 0 to ensure that after
+                // autofill() is called, getAutofillValue() == the value that was originally passed
+                // into autofill(). Without clear(), the view will not turn yellow when updated.
+                clear()
+                val year = Integer.parseInt(ccExpYear.selectedItem.toString())
+                val month = ccExpMonth.selectedItemPosition
+                set(Calendar.YEAR, year)
+                set(Calendar.MONTH, month)
+            }.timeInMillis)
+
+    override fun autofill(value: AutofillValue) {
+        if (!value.isDate) {
+            return
+        }
+        val calendar = Calendar.getInstance().apply {
+            timeInMillis = value.dateValue
+        }
+        val month = calendar.get(Calendar.MONTH)
+        val year = calendar.get(Calendar.YEAR)
+        ccExpMonth.setSelection(month)
+        ccExpYear.setSelection(year - startYear)
+    }
+
+    override fun getAutofillType() = View.AUTOFILL_TYPE_DATE
+
+    fun reset() {
+        ccExpMonth.setSelection(0)
+        ccExpYear.setSelection(0)
+    }
+
+    companion object {
+        private const val CC_EXP_YEARS_COUNT = 5
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt
index c5a7989..36c4343 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt
@@ -31,13 +31,10 @@
 import android.view.autofill.AutofillValue
 import android.widget.EditText
 import android.widget.TextView
-
-import com.example.android.autofillframework.R
-
-import java.util.ArrayList
-import java.util.Arrays
-
+import com.example.android.autofillframework.CommonUtil.TAG
 import com.example.android.autofillframework.CommonUtil.bundleToString
+import com.example.android.autofillframework.R
+import java.util.Arrays
 
 
 /**
@@ -45,65 +42,48 @@
  */
 class CustomVirtualView(context: Context, attrs: AttributeSet) : View(context, attrs) {
 
-    private val mLines = ArrayList<Line>()
-    private val mItems = SparseArray<Item>()
-    private val mAfm: AutofillManager
-
-    private var mFocusedLine: Line? = null
-    private val mTextPaint: Paint
-    private val mTextHeight: Int
-    private val mTopMargin: Int
-    private val mLeftMargin: Int
-    private val mVerticalGap: Int
-    private val mLineLength: Int
-    private val mFocusedColor: Int
-    private val mUnfocusedColor: Int
-
-    private val mUsernameLine: Line
-    private val mPasswordLine: Line
-
-    init {
-
-        mAfm = context.getSystemService(AutofillManager::class.java)
-
-        mTextPaint = Paint()
-
-        mUnfocusedColor = Color.BLACK
-        mFocusedColor = Color.RED
-        mTextPaint.style = Style.FILL
-        mTopMargin = 100
-        mLeftMargin = 100
-        mTextHeight = 90
-        mVerticalGap = 10
-
-        mLineLength = mTextHeight + mVerticalGap
-        mTextPaint.textSize = mTextHeight.toFloat()
-        mUsernameLine = addLine("usernameField", context.getString(R.string.username_label),
-                arrayOf(View.AUTOFILL_HINT_USERNAME), "         ", true)
-        mPasswordLine = addLine("passwordField", context.getString(R.string.password_label),
-                arrayOf(View.AUTOFILL_HINT_PASSWORD), "         ", false)
-
-        Log.d(TAG, "Text height: " + mTextHeight)
+    val usernameText: CharSequence
+        get() = usernameLine.fieldTextItem.text
+    val passwordText: CharSequence
+        get() = passwordLine.fieldTextItem.text
+    private var nextId: Int = 0
+    private val lines = ArrayList<Line>()
+    private val items = SparseArray<Item>()
+    private val autofillManager = context.getSystemService(AutofillManager::class.java)
+    private var focusedLine: Line? = null
+    private val textHeight = 90
+    private val textPaint = Paint().apply {
+        style = Style.FILL
+        textSize = textHeight.toFloat()
     }
+    private val topMargin = 100
+    private val leftMargin = 100
+    private val verticalGap = 10
+    private val lineLength = textHeight + verticalGap
+    private val focusedColor = Color.RED
+    private val unfocusedColor = Color.BLACK
+    private val usernameLine = addLine("usernameField", context.getString(R.string.username_label),
+            arrayOf(View.AUTOFILL_HINT_USERNAME), "         ", true)
+    private val passwordLine = addLine("passwordField", context.getString(R.string.password_label),
+            arrayOf(View.AUTOFILL_HINT_PASSWORD), "         ", false)
 
     override fun autofill(values: SparseArray<AutofillValue>) {
-        // User has just selected a Dataset from the list of Autofill suggestions and the Dataset's
-        // AutofillValue gets passed into this method.
-        Log.d(TAG, "autoFill(): " + values)
-        for (i in 0..values.size() - 1) {
+        // 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.
+        Log.d(TAG, "autofill(): " + values)
+        for (i in 0 until values.size()) {
             val id = values.keyAt(i)
             val value = values.valueAt(i)
-            val item = mItems.get(id)
-            if (item == null) {
-                Log.w(TAG, "No item for id " + id)
-                return
+            items[id]?.apply {
+                if (editable) {
+                    // Set the item's text to the text wrapped in the AutofillValue.
+                    text = value.textValue
+                } else {
+                    Log.w(TAG, "Item for autofillId $id is not editable: $this")
+                }
             }
-            if (!item.editable) {
-                Log.w(TAG, "Item for id $id is not editable: $item")
-                return
-            }
-            // Set the item's text to the text wrapped in the AutofillValue.
-            item.text = value.textValue
         }
         postInvalidate()
     }
@@ -111,23 +91,23 @@
     override fun onProvideAutofillVirtualStructure(structure: ViewStructure, flags: Int) {
         // Build a ViewStructure to pack in AutoFillService requests.
         structure.setClassName(javaClass.name)
-        val childrenSize = mItems.size()
+        val childrenSize = items.size()
         Log.d(TAG, "onProvideAutofillVirtualStructure(): flags = " + flags + ", items = "
                 + childrenSize + ", extras: " + bundleToString(structure.extras))
         var index = structure.addChildCount(childrenSize)
-        for (i in 0..childrenSize - 1) {
-            val item = mItems.valueAt(i)
+        for (i in 0 until childrenSize) {
+            val item = items.valueAt(i)
             Log.d(TAG, "Adding new child at index $index: $item")
-            val child = structure.newChild(index)
-            child.setAutofillId(structure, item.id)
-            child.setAutofillHints(item.hints)
-            child.setAutofillType(item.type)
-            child.setDataIsSensitive(!item.sanitized)
-            child.text = item.text
-            child.setAutofillValue(AutofillValue.forText(item.text))
-            child.setFocused(item.focused)
-            child.setId(item.id, context.packageName, null, item.line.idEntry)
-            child.setClassName(item.className)
+            structure.newChild(index).apply {
+                setAutofillId(structure.autofillId, item.id)
+                setAutofillHints(item.hints)
+                setAutofillType(item.type)
+                setDataIsSensitive(!item.sanitized)
+                setAutofillValue(AutofillValue.forText(item.text))
+                setFocused(item.focused)
+                setId(item.id, context.packageName, null, item.line.idEntry)
+                setClassName(item.className)
+            }
             index++
         }
     }
@@ -135,75 +115,71 @@
     override fun onDraw(canvas: Canvas) {
         super.onDraw(canvas)
 
-        Log.d(TAG, "onDraw: " + mLines.size + " lines; canvas:" + canvas)
+        Log.d(TAG, "onDraw: " + lines.size + " lines; canvas:" + canvas)
         var x: Float
-        var y = (mTopMargin + mLineLength).toFloat()
-        for (i in mLines.indices) {
-            x = mLeftMargin.toFloat()
-            val line = mLines[i]
-            Log.v(TAG, "Drawing '" + line + "' at " + x + "x" + y)
-            mTextPaint.color = if (line.fieldTextItem.focused) mFocusedColor else mUnfocusedColor
-            val readOnlyText = line.labelItem.text.toString() + ":  ["
-            val writeText = line.fieldTextItem.text.toString() + "]"
+        var y = (topMargin + lineLength).toFloat()
+
+        lines.forEach {
+            x = leftMargin.toFloat()
+            Log.v(TAG, "Drawing $it at x=$x, y=$y")
+            textPaint.color = if (it.fieldTextItem.focused) focusedColor else unfocusedColor
+            val readOnlyText = it.labelItem.text.toString() + ":  ["
+            val writeText = it.fieldTextItem.text.toString() + "]"
             // Paints the label first...
-            canvas.drawText(readOnlyText, x, y, mTextPaint)
+            canvas.drawText(readOnlyText, x, y, textPaint)
             // ...then paints the edit text and sets the proper boundary
-            val deltaX = mTextPaint.measureText(readOnlyText)
+            val deltaX = textPaint.measureText(readOnlyText)
             x += deltaX
-            line.bounds.set(x.toInt(), (y - mLineLength).toInt(),
-                    (x + mTextPaint.measureText(writeText)).toInt(), y.toInt())
-            Log.d(TAG, "setBounds(" + x + ", " + y + "): " + line.bounds)
-            canvas.drawText(writeText, x, y, mTextPaint)
-            y += mLineLength.toFloat()
+            it.bounds.set(x.toInt(), (y - lineLength).toInt(),
+                    (x + textPaint.measureText(writeText)).toInt(), y.toInt())
+            Log.d(TAG, "setBounds(" + x + ", " + y + "): " + it.bounds)
+            canvas.drawText(writeText, x, y, textPaint)
+            y += lineLength.toFloat()
         }
     }
 
     override fun onTouchEvent(event: MotionEvent): Boolean {
         val y = event.y.toInt()
-        Log.d(TAG, "Touched: y=$y, range=$mLineLength, top=$mTopMargin")
-        var lowerY = mTopMargin
+        Log.d(TAG, "Touched: y=$y, range=$lineLength, top=$topMargin")
+        var lowerY = topMargin
         var upperY = -1
-        for (i in mLines.indices) {
-            upperY = lowerY + mLineLength
-            val line = mLines[i]
-            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)
-                }
+        for (line in lines) {
+            upperY = lowerY + lineLength
+            Log.d(TAG, "Line $line ranges from $lowerY to $upperY")
+            if (y in lowerY..upperY) {
+                Log.d(TAG, "Removing focus from " + focusedLine)
+                focusedLine?.changeFocus(false)
                 Log.d(TAG, "Changing focus to " + line)
-                mFocusedLine = line
-                mFocusedLine!!.changeFocus(true)
+                focusedLine = line.apply { changeFocus(true) }
                 invalidate()
                 break
             }
-            lowerY += mLineLength
+            lowerY += lineLength
         }
         return super.onTouchEvent(event)
     }
 
-    val usernameText: CharSequence
-        get() = mUsernameLine.fieldTextItem.text
-
-    val passwordText: CharSequence
-        get() = mPasswordLine.fieldTextItem.text
-
     fun resetFields() {
-        mUsernameLine.reset()
-        mPasswordLine.reset()
+        usernameLine.reset()
+        passwordLine.reset()
         postInvalidate()
     }
 
-    private fun addLine(idEntry: String, label: String, hints: Array<String>, text: String, sanitized: Boolean): Line {
-        val line = Line(idEntry, label, hints, text, sanitized)
-        mLines.add(line)
-        mItems.put(line.labelItem.id, line.labelItem)
-        mItems.put(line.fieldTextItem.id, line.fieldTextItem)
-        return line
+    private fun addLine(idEntry: String, label: String, hints: Array<String>, text: String,
+            sanitized: Boolean) = Line(idEntry, label, hints, text, sanitized).also {
+        lines.add(it)
+        items.apply {
+            put(it.labelItem.id, it.labelItem)
+            put(it.fieldTextItem.id, it.fieldTextItem)
+        }
     }
 
-    private class Item internal constructor(val line: Line, val id: Int, val hints: Array<String>?, val type: Int, var text: CharSequence, val editable: Boolean, val sanitized: Boolean) {
+    private inner class Item internal constructor(
+            val line: Line,
+            val id: Int,
+            val hints: Array<String>?,
+            val type: Int, var text: CharSequence, val editable: Boolean,
+            val sanitized: Boolean) {
         var focused = false
 
         override fun toString(): String {
@@ -217,39 +193,35 @@
             get() = if (editable) EditText::class.java.name else TextView::class.java.name
     }
 
-    private inner class Line constructor(val idEntry: String, label: String, hints: Array<String>, text: String, sanitized: Boolean) {
+    private inner class Line constructor(val idEntry: String, label: String, hints: Array<String>,
+            text: String, sanitized: Boolean) {
 
         // Boundaries of the text field, relative to the CustomView
         internal val bounds = Rect()
-        var labelItem: Item
-        var fieldTextItem: Item
-
-        init {
-            this.labelItem = Item(this, ++nextId, null, View.AUTOFILL_TYPE_NONE, label, false, true)
-            this.fieldTextItem = Item(this, ++nextId, hints, View.AUTOFILL_TYPE_TEXT, text, true, sanitized)
-        }
+        var labelItem: Item = Item(this, ++nextId, null, View.AUTOFILL_TYPE_NONE, label, false, true)
+        var fieldTextItem: Item = Item(this, ++nextId, hints, View.AUTOFILL_TYPE_TEXT, text, true, sanitized)
 
         internal fun changeFocus(focused: Boolean) {
             fieldTextItem.focused = focused
             if (focused) {
                 val absBounds = absCoordinates
                 Log.d(TAG, "focus gained on " + fieldTextItem.id + "; absBounds=" + absBounds)
-                mAfm.notifyViewEntered(this@CustomVirtualView, fieldTextItem.id, absBounds)
+                autofillManager.notifyViewEntered(this@CustomVirtualView, fieldTextItem.id, absBounds)
             } else {
                 Log.d(TAG, "focus lost on " + fieldTextItem.id)
-                mAfm.notifyViewExited(this@CustomVirtualView, fieldTextItem.id)
+                autofillManager.notifyViewExited(this@CustomVirtualView, fieldTextItem.id)
             }
         }
 
-        private // Must offset the boundaries so they're relative to the CustomView.
-        val absCoordinates: Rect
+        private val absCoordinates: Rect
+                // Must offset the boundaries so they're relative to the CustomView.
             get() {
                 val offset = IntArray(2)
                 getLocationOnScreen(offset)
                 val absBounds = Rect(bounds.left + offset[0],
                         bounds.top + offset[1],
                         bounds.right + offset[0], bounds.bottom + offset[1])
-                Log.v(TAG, "getAbsCoordinates() for " + fieldTextItem.id + ": bounds=" + bounds
+                Log.v(TAG, "absCoordinates for " + fieldTextItem.id + ": bounds=" + bounds
                         + " offset: " + Arrays.toString(offset) + " absBounds: " + absBounds)
                 return absBounds
             }
@@ -263,11 +235,4 @@
                     fieldTextItem.focused
         }
     }
-
-    companion object {
-
-        private val TAG = "CustomView"
-
-        private var nextId: Int = 0
-    }
 }
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/EmailComposeActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/EmailComposeActivity.kt
new file mode 100644
index 0000000..7b23b61
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/EmailComposeActivity.kt
@@ -0,0 +1,43 @@
+/*
+ * 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 com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.email_compose_activity.sendButton
+
+class EmailComposeActivity : AppCompatActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.email_compose_activity)
+        sendButton.setOnClickListener {
+            startActivity(WelcomeActivity.getStartActivityIntent(this@EmailComposeActivity))
+            finish()
+        }
+    }
+
+    companion object {
+
+        fun getStartActivityIntent(context: Context): Intent {
+            val intent = Intent(context, EmailComposeActivity::class.java)
+            return intent
+        }
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/InfoButton.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/InfoButton.kt
new file mode 100644
index 0000000..5b480b8
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/InfoButton.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.v7.app.AlertDialog
+import android.support.v7.widget.AppCompatImageButton
+import android.util.AttributeSet
+import com.example.android.autofillframework.R
+
+class InfoButton @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyleAttr: Int = 0
+) : AppCompatImageButton(context, attrs, defStyleAttr) {
+
+    init {
+        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.InfoButton,
+                defStyleAttr, 0)
+        val infoText = typedArray.getString(R.styleable.InfoButton_dialogText)
+        typedArray.recycle()
+        setInfoText(infoText)
+    }
+
+    fun setInfoText(infoText: String) {
+        setOnClickListener {
+            AlertDialog.Builder(this@InfoButton.context).setMessage(infoText).create().show()
+        }
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.kt
deleted file mode 100644
index 8a73960..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.kt
+++ /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.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.Button
-import android.widget.EditText
-import android.widget.Toast
-
-import com.example.android.autofillframework.R
-
-class LoginActivity : AppCompatActivity() {
-
-    private var mUsernameEditText: EditText? = null
-    private var mPasswordEditText: EditText? = null
-    private var mLoginButton: Button? = null
-    private var mClearButton: Button? = null
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-
-        setContentView(R.layout.login_activity)
-
-        mLoginButton = findViewById(R.id.login) as Button
-        mClearButton = findViewById(R.id.clear) as Button
-        mUsernameEditText = findViewById(R.id.usernameField) as EditText
-        mPasswordEditText = findViewById(R.id.passwordField) as EditText
-        mLoginButton!!.setOnClickListener { login() }
-        mClearButton!!.setOnClickListener { resetFields() }
-    }
-
-    private fun resetFields() {
-        mUsernameEditText!!.setText("")
-        mPasswordEditText!!.setText("")
-    }
-
-    /**
-     * Emulates a login action.
-     */
-    private fun login() {
-        val username = mUsernameEditText!!.text.toString()
-        val password = mPasswordEditText!!.text.toString()
-        val valid = isValidCredentials(username, password)
-        if (valid) {
-            val intent = WelcomeActivity.getStartActivityIntent(this@LoginActivity)
-            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.
-     */
-    fun isValidCredentials(username: String?, password: String?): Boolean {
-        return username != null && password != null && username == password
-    }
-
-    companion object {
-
-        fun getStartActivityIntent(context: Context): Intent {
-            val intent = Intent(context, LoginActivity::class.java)
-            return intent
-        }
-    }
-}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.kt
index b47daa1..0722e14 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.kt
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/MainActivity.kt
@@ -15,13 +15,16 @@
  */
 package com.example.android.autofillframework.app
 
-import android.app.Activity
-import android.content.Intent
 import android.os.Bundle
 import android.support.v7.app.AppCompatActivity
 import android.view.View
-
 import com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.activity_main.creditCardCheckoutButton
+import kotlinx.android.synthetic.main.activity_main.creditCardCompoundViewButton
+import kotlinx.android.synthetic.main.activity_main.emailComposeButton
+import kotlinx.android.synthetic.main.activity_main.standardLoginWithAutoCompleteButton
+import kotlinx.android.synthetic.main.activity_main.standardViewSignInButton
+import kotlinx.android.synthetic.main.activity_main.virtualViewSignInButton
 
 /**
  * This is used to launch sample activities that showcase autofill.
@@ -31,23 +34,23 @@
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_main)
-        findViewById(R.id.standardViewSignInButton).setOnClickListener { standardViewSignIn() }
-        findViewById(R.id.virtualViewSignInButton).setOnClickListener { virtualViewSignIn() }
-        findViewById(R.id.creditCardCheckoutButton).setOnClickListener { creditCardCheckout() }
-    }
-
-    private fun creditCardCheckout() {
-        val intent = CreditCardActivity.getStartActivityIntent(this)
-        startActivity(intent)
-    }
-
-    private fun standardViewSignIn() {
-        val intent = LoginActivity.getStartActivityIntent(this)
-        startActivity(intent)
-    }
-
-    private fun virtualViewSignIn() {
-        val intent = VirtualLoginActivity.getStartActivityIntent(this)
-        startActivity(intent)
+        standardViewSignInButton.setNavigationButtonClickListener(View.OnClickListener {
+            startActivity(StandardSignInActivity.getStartActivityIntent(this@MainActivity))
+        })
+        virtualViewSignInButton.setNavigationButtonClickListener(View.OnClickListener {
+            startActivity(VirtualSignInActivity.getStartActivityIntent(this@MainActivity))
+        })
+        creditCardCheckoutButton.setNavigationButtonClickListener(View.OnClickListener {
+            startActivity(CreditCardActivity.getStartActivityIntent(this@MainActivity))
+        })
+        standardLoginWithAutoCompleteButton.setNavigationButtonClickListener(View.OnClickListener {
+            startActivity(StandardAutoCompleteSignInActivity.getStartActivityIntent(this@MainActivity))
+        })
+        emailComposeButton.setNavigationButtonClickListener(View.OnClickListener {
+            startActivity(EmailComposeActivity.getStartActivityIntent(this@MainActivity))
+        })
+        creditCardCompoundViewButton.setNavigationButtonClickListener(View.OnClickListener {
+            startActivity(CreditCardCompoundViewActivity.getStartActivityIntent(this@MainActivity))
+        })
     }
 }
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/NavigationItem.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/NavigationItem.kt
new file mode 100644
index 0000000..be09a99
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/NavigationItem.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.graphics.PorterDuff
+import android.support.annotation.ColorRes
+import android.support.v4.content.ContextCompat
+import android.support.v7.app.AlertDialog
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.navigation_item.view.buttonLabel
+import kotlinx.android.synthetic.main.navigation_item.view.cardView
+import kotlinx.android.synthetic.main.navigation_item.view.infoButton
+
+class NavigationItem @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyleAttr: Int = 0
+) : FrameLayout(context, attrs, defStyleAttr) {
+
+    init {
+        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.NavigationItem,
+                defStyleAttr, 0)
+        val labelText = typedArray.getString(R.styleable.NavigationItem_labelText)
+        val infoText = typedArray.getString(R.styleable.NavigationItem_infoText)
+        val logoDrawable = typedArray.getDrawable(R.styleable.NavigationItem_itemLogo)
+        @ColorRes val colorRes = typedArray.getResourceId(R.styleable.NavigationItem_imageColor, 0)
+        val imageColor = ContextCompat.getColor(getContext(), colorRes)
+        typedArray.recycle()
+        LayoutInflater.from(context).inflate(R.layout.navigation_item, this)
+        logoDrawable?.setColorFilter(imageColor, PorterDuff.Mode.SRC_IN)
+        buttonLabel.apply {
+            text = labelText
+            setCompoundDrawablesRelativeWithIntrinsicBounds(logoDrawable, null, null, null)
+        }
+        infoButton.apply {
+            setOnClickListener {
+                AlertDialog.Builder(this@NavigationItem.context)
+                        .setMessage(infoText).create().show()
+            }
+            setColorFilter(imageColor)
+        }
+    }
+
+    fun setNavigationButtonClickListener(l: View.OnClickListener?) {
+        cardView.setOnClickListener(l)
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/StandardAutoCompleteSignInActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/StandardAutoCompleteSignInActivity.kt
new file mode 100644
index 0000000..2e154fb
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/StandardAutoCompleteSignInActivity.kt
@@ -0,0 +1,121 @@
+/*
+ * 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.Toast
+import com.example.android.autofillframework.CommonUtil.TAG
+import com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.login_with_autocomplete_activity.clear
+import kotlinx.android.synthetic.main.login_with_autocomplete_activity.login
+import kotlinx.android.synthetic.main.login_with_autocomplete_activity.passwordField
+import kotlinx.android.synthetic.main.login_with_autocomplete_activity.usernameField
+
+class StandardAutoCompleteSignInActivity : AppCompatActivity() {
+    private var autofillReceived = false
+    private lateinit var autofillCallback: AutofillManager.AutofillCallback
+    private lateinit var autofillManager: AutofillManager
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        setContentView(R.layout.login_with_autocomplete_activity)
+
+        login.setOnClickListener { submitLogin() }
+        clear.setOnClickListener { resetFields() }
+        autofillCallback = MyAutofillCallback()
+        autofillManager = getSystemService(AutofillManager::class.java)
+        val mockAutocompleteAdapter = ArrayAdapter.createFromResource(this, R.array.mock_autocomplete_sign_in_suggestions,
+                android.R.layout.simple_dropdown_item_1line)
+        usernameField.setAdapter(mockAutocompleteAdapter)
+    }
+
+    override fun onResume() {
+        super.onResume()
+        autofillManager.registerCallback(autofillCallback)
+    }
+
+    override fun onPause() {
+        super.onPause()
+        autofillManager.unregisterCallback(autofillCallback)
+    }
+
+    private fun resetFields() {
+        usernameField.setText("")
+        passwordField.setText("")
+    }
+
+    /**
+     * Emulates a login action.
+     */
+    private fun submitLogin() {
+        val username = usernameField.text.toString()
+        val password = passwordField.text.toString()
+        val valid = isValidCredentials(username, password)
+        if (valid) {
+            val intent = WelcomeActivity.getStartActivityIntent(this@StandardAutoCompleteSignInActivity)
+            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.
+     */
+    fun isValidCredentials(username: String?, password: String?): Boolean {
+        return username != null && password != null && username == password
+    }
+
+    private inner class MyAutofillCallback : AutofillManager.AutofillCallback() {
+        override fun onAutofillEvent(view: View, event: Int) {
+            super.onAutofillEvent(view, event)
+            if (view is AutoCompleteTextView) {
+                when (event) {
+                    AutofillManager.AutofillCallback.EVENT_INPUT_UNAVAILABLE,
+                    AutofillManager.AutofillCallback.EVENT_INPUT_HIDDEN -> {
+                        if (!autofillReceived) {
+                            view.showDropDown()
+                        }
+                    }
+                    AutofillManager.AutofillCallback.EVENT_INPUT_SHOWN -> {
+                        autofillReceived = true
+                        view.setAdapter(null)
+                    }
+                    else -> Log.d(TAG, "Unexpected callback: " + event)
+                }
+            }
+        }
+    }
+
+    companion object {
+
+        fun getStartActivityIntent(context: Context): Intent {
+            val intent = Intent(context, StandardAutoCompleteSignInActivity::class.java)
+            return intent
+        }
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/StandardSignInActivity.kt
similarity index 65%
copy from prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt
copy to prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/StandardSignInActivity.kt
index 198ff9d..971bd16 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/StandardSignInActivity.kt
@@ -15,45 +15,44 @@
  */
 package com.example.android.autofillframework.app
 
-import android.app.Activity
+
 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.Toast
-
 import com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.login_activity.clear
+import kotlinx.android.synthetic.main.login_activity.login
+import kotlinx.android.synthetic.main.login_activity.passwordField
+import kotlinx.android.synthetic.main.login_activity.usernameField
 
 
-class VirtualLoginActivity : AppCompatActivity() {
-
-    private var mCustomVirtualView: CustomVirtualView? = null
+class StandardSignInActivity : AppCompatActivity() {
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-
-        setContentView(R.layout.virtual_login_activity)
-
-        mCustomVirtualView = findViewById(R.id.custom_view) as CustomVirtualView
-        findViewById(R.id.login).setOnClickListener { login() }
-        findViewById(R.id.clear).setOnClickListener { resetFields() }
+        setContentView(R.layout.login_activity)
+        login.setOnClickListener { login() }
+        clear.setOnClickListener { resetFields() }
     }
 
     private fun resetFields() {
-        mCustomVirtualView!!.resetFields()
+        usernameField.setText("")
+        passwordField.setText("")
     }
 
     /**
      * Emulates a login action.
      */
     private fun login() {
-        val username = mCustomVirtualView!!.usernameText.toString()
-        val password = mCustomVirtualView!!.passwordText.toString()
+        val username = usernameField.text.toString()
+        val password = passwordField.text.toString()
         val valid = isValidCredentials(username, password)
         if (valid) {
-            val intent = WelcomeActivity.getStartActivityIntent(this@VirtualLoginActivity)
+            val intent = WelcomeActivity.getStartActivityIntent(this@StandardSignInActivity)
             startActivity(intent)
+            finish()
         } else {
             Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show()
         }
@@ -63,15 +62,15 @@
      * Dummy implementation for demo purposes. A real service should use secure mechanisms to
      * authenticate users.
      */
-    fun isValidCredentials(username: String?, password: String?): Boolean {
-        return username != null && password != null && username == password
+    fun isValidCredentials(username: String, password: String): Boolean {
+        return username == password
     }
 
     companion object {
 
         fun getStartActivityIntent(context: Context): Intent {
-            val intent = Intent(context, VirtualLoginActivity::class.java)
+            val intent = Intent(context, StandardSignInActivity::class.java)
             return intent
         }
     }
-}
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualSignInActivity.kt
similarity index 72%
rename from prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt
rename to prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualSignInActivity.kt
index 198ff9d..6d86da9 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualSignInActivity.kt
@@ -15,45 +15,43 @@
  */
 package com.example.android.autofillframework.app
 
-import android.app.Activity
 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.Toast
-
 import com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.virtual_login_activity.clear
+import kotlinx.android.synthetic.main.virtual_login_activity.custom_view
+import kotlinx.android.synthetic.main.virtual_login_activity.login
 
 
-class VirtualLoginActivity : AppCompatActivity() {
-
-    private var mCustomVirtualView: CustomVirtualView? = null
+class VirtualSignInActivity : AppCompatActivity() {
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
         setContentView(R.layout.virtual_login_activity)
 
-        mCustomVirtualView = findViewById(R.id.custom_view) as CustomVirtualView
-        findViewById(R.id.login).setOnClickListener { login() }
-        findViewById(R.id.clear).setOnClickListener { resetFields() }
+        login.setOnClickListener { submitLogin() }
+        clear.setOnClickListener { resetFields() }
     }
 
     private fun resetFields() {
-        mCustomVirtualView!!.resetFields()
+        custom_view.resetFields()
     }
 
     /**
      * Emulates a login action.
      */
-    private fun login() {
-        val username = mCustomVirtualView!!.usernameText.toString()
-        val password = mCustomVirtualView!!.passwordText.toString()
+    private fun submitLogin() {
+        val username = custom_view.usernameText.toString()
+        val password = custom_view.passwordText.toString()
         val valid = isValidCredentials(username, password)
         if (valid) {
-            val intent = WelcomeActivity.getStartActivityIntent(this@VirtualLoginActivity)
+            val intent = WelcomeActivity.getStartActivityIntent(this@VirtualSignInActivity)
             startActivity(intent)
+            finish()
         } else {
             Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show()
         }
@@ -70,7 +68,7 @@
     companion object {
 
         fun getStartActivityIntent(context: Context): Intent {
-            val intent = Intent(context, VirtualLoginActivity::class.java)
+            val intent = Intent(context, VirtualSignInActivity::class.java)
             return intent
         }
     }
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.kt
index 0147518..db8bf67 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.kt
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/WelcomeActivity.kt
@@ -15,18 +15,37 @@
  */
 package com.example.android.autofillframework.app
 
-import android.app.Activity
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
-
+import android.os.CountDownTimer
+import android.support.v7.app.AppCompatActivity
 import com.example.android.autofillframework.R
+import kotlinx.android.synthetic.main.welcome_activity.countdownText
+import java.lang.Math.toIntExact
 
-class WelcomeActivity : Activity() {
+
+class WelcomeActivity : AppCompatActivity() {
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.welcome_activity)
+        object : CountDownTimer(5000, 1000) {
+
+            override fun onTick(millisUntilFinished: Long) {
+                val secondsRemaining = toIntExact(millisUntilFinished / 1000)
+                countdownText.text = getResources()
+                        .getQuantityString(R.plurals.welcome_page_countdown, secondsRemaining,
+                                secondsRemaining)
+            }
+
+            override fun onFinish() {
+                if (!this@WelcomeActivity.isFinishing) {
+                    finish()
+                }
+            }
+
+        }.start()
     }
 
     companion object {
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AuthActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AuthActivity.kt
new file mode 100644
index 0000000..e02a311
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AuthActivity.kt
@@ -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.autofillframework.multidatasetservice
+
+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.os.Bundle
+import android.service.autofill.Dataset
+import android.service.autofill.FillResponse
+import android.support.v7.app.AppCompatActivity
+import android.util.Log
+import android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE
+import android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT
+import android.widget.Toast
+import com.example.android.autofillframework.CommonUtil.EXTRA_DATASET_NAME
+import com.example.android.autofillframework.CommonUtil.EXTRA_FOR_RESPONSE
+import com.example.android.autofillframework.CommonUtil.TAG
+import com.example.android.autofillframework.R
+import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsAutofillRepository
+import com.example.android.autofillframework.multidatasetservice.settings.MyPreferences
+import kotlinx.android.synthetic.main.multidataset_service_auth_activity.cancel
+import kotlinx.android.synthetic.main.multidataset_service_auth_activity.login
+import kotlinx.android.synthetic.main.multidataset_service_auth_activity.master_password
+
+/**
+ * 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.
+ */
+class AuthActivity : AppCompatActivity() {
+
+    private var replyIntent: Intent? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.multidataset_service_auth_activity)
+        login.setOnClickListener { submitLogin() }
+        cancel.setOnClickListener {
+            onFailure()
+            this@AuthActivity.finish()
+        }
+    }
+
+    private fun submitLogin() {
+        val password = master_password.text
+        if (password.toString() == MyPreferences.getMasterPassword(this@AuthActivity)) {
+            onSuccess()
+        } else {
+            Toast.makeText(this, "Password incorrect", Toast.LENGTH_SHORT).show()
+            onFailure()
+        }
+        finish()
+    }
+
+    override fun finish() {
+        if (replyIntent != null) {
+            setResult(Activity.RESULT_OK, replyIntent)
+        } else {
+            setResult(Activity.RESULT_CANCELED)
+        }
+        super.finish()
+    }
+
+    private fun onFailure() {
+        Log.w(TAG, "Failed auth.")
+        replyIntent = null
+    }
+
+    private fun onSuccess() {
+        val intent = intent
+        val forResponse = intent.getBooleanExtra(EXTRA_FOR_RESPONSE, true)
+        val structure = intent.getParcelableExtra<AssistStructure>(EXTRA_ASSIST_STRUCTURE)
+        val parser = StructureParser(structure)
+        parser.parseForFill()
+        val autofillFields = parser.autofillFields
+        replyIntent = Intent()
+        val clientFormDataMap = SharedPrefsAutofillRepository
+                .getFilledAutofillFieldCollection(this, autofillFields.focusedAutofillHints, autofillFields.allAutofillHints)
+        if (forResponse) {
+            AutofillHelper.newResponse(this, false, autofillFields, clientFormDataMap)?.let(this::setResponseIntent)
+        } else {
+            val datasetName = intent.getStringExtra(EXTRA_DATASET_NAME)
+            clientFormDataMap?.let {
+                it[datasetName]?.let { clientFormData ->
+                    AutofillHelper.newDataset(this, autofillFields, clientFormData, false)?.let(this::setDatasetIntent)
+                }
+            }
+        }
+    }
+
+    private fun setResponseIntent(fillResponse: FillResponse) {
+        replyIntent?.putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse)
+    }
+
+    private fun setDatasetIntent(dataset: Dataset) {
+        replyIntent?.putExtra(EXTRA_AUTHENTICATION_RESULT, dataset)
+    }
+
+    companion object {
+
+        // Unique autofillId for dataset intents.
+        private var datasetPendingIntentId = 0
+
+        internal fun getAuthIntentSenderForResponse(context: Context): IntentSender {
+            val intent = Intent(context, AuthActivity::class.java)
+            return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
+                    .intentSender
+        }
+
+        internal fun getAuthIntentSenderForDataset(context: Context, datasetName: String): IntentSender {
+            val intent = Intent(context, AuthActivity::class.java)
+            intent.putExtra(EXTRA_DATASET_NAME, datasetName)
+            intent.putExtra(EXTRA_FOR_RESPONSE, false)
+            return PendingIntent.getActivity(context, ++datasetPendingIntentId, intent,
+                    PendingIntent.FLAG_CANCEL_CURRENT).intentSender
+        }
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.kt
new file mode 100644
index 0000000..bf12c57
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.kt
@@ -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.autofillframework.multidatasetservice
+
+import android.app.assist.AssistStructure.ViewNode;
+import android.service.autofill.SaveInfo
+import android.view.View
+import android.view.autofill.AutofillId
+
+/**
+ * A stripped down version of a [ViewNode] that contains only autofill-relevant metadata. It also
+ * contains a `saveType` flag that is calculated based on the [ViewNode]'s autofill hints.
+ */
+class AutofillFieldMetadata(view: ViewNode) {
+    var saveType = 0
+        private set
+
+    val autofillHints = view.autofillHints.filter(AutofillHelper::isValidHint).toTypedArray()
+    val autofillId: AutofillId = view.autofillId
+    val autofillType: Int = view.autofillType
+    val autofillOptions: Array<CharSequence>? = view.autofillOptions
+    val isFocused: Boolean = view.isFocused
+
+    init {
+        updateSaveTypeFromHints()
+    }
+
+    /**
+     * When the [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.
+     */
+    fun getAutofillOptionIndex(value: CharSequence): Int {
+        if (autofillOptions != null) {
+            return autofillOptions.indexOf(value)
+        } else {
+            return -1
+        }
+    }
+
+    private fun updateSaveTypeFromHints() {
+        saveType = 0
+        for (hint in autofillHints) {
+            when (hint) {
+                View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE,
+                View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY,
+                View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
+                View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR,
+                View.AUTOFILL_HINT_CREDIT_CARD_NUMBER,
+                View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE -> {
+                    saveType = saveType or SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD
+                }
+                View.AUTOFILL_HINT_EMAIL_ADDRESS -> {
+                    saveType = saveType or SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS
+                }
+                View.AUTOFILL_HINT_PHONE, View.AUTOFILL_HINT_NAME -> {
+                    saveType = saveType or SaveInfo.SAVE_DATA_TYPE_GENERIC
+                }
+                View.AUTOFILL_HINT_PASSWORD -> {
+                    saveType = saveType or SaveInfo.SAVE_DATA_TYPE_PASSWORD
+                    saveType = saveType and SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS.inv()
+                    saveType = saveType and SaveInfo.SAVE_DATA_TYPE_USERNAME.inv()
+                }
+                View.AUTOFILL_HINT_POSTAL_ADDRESS,
+                View.AUTOFILL_HINT_POSTAL_CODE -> {
+                    saveType = saveType or SaveInfo.SAVE_DATA_TYPE_ADDRESS
+                }
+                View.AUTOFILL_HINT_USERNAME -> {
+                    saveType = saveType or SaveInfo.SAVE_DATA_TYPE_USERNAME
+                }
+            }
+        }
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadataCollection.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadataCollection.kt
new file mode 100644
index 0000000..1044ec7
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadataCollection.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.example.android.autofillframework.multidatasetservice
+
+import android.view.autofill.AutofillId
+
+/**
+ * Data structure that stores a collection of `AutofillFieldMetadata`s. Contains all of the client's `View`
+ * hierarchy autofill-relevant metadata.
+ */
+data class AutofillFieldMetadataCollection @JvmOverloads constructor(
+        val autofillIds: ArrayList<AutofillId> = ArrayList<AutofillId>(),
+        val allAutofillHints: ArrayList<String> = ArrayList<String>(),
+        val focusedAutofillHints: ArrayList<String> = ArrayList<String>()
+) {
+
+    private val autofillHintsToFieldsMap = HashMap<String, MutableList<AutofillFieldMetadata>>()
+    var saveType = 0
+        private set
+
+    fun add(autofillFieldMetadata: AutofillFieldMetadata) {
+        saveType = saveType or autofillFieldMetadata.saveType
+        autofillIds.add(autofillFieldMetadata.autofillId)
+        val hintsList = autofillFieldMetadata.autofillHints
+        allAutofillHints.addAll(hintsList)
+        if (autofillFieldMetadata.isFocused) {
+            focusedAutofillHints.addAll(hintsList)
+        }
+        autofillFieldMetadata.autofillHints.forEach {
+            val fields = autofillHintsToFieldsMap[it] ?: ArrayList<AutofillFieldMetadata>()
+            autofillHintsToFieldsMap[it] = fields
+            fields.add(autofillFieldMetadata)
+        }
+    }
+
+    fun getFieldsForHint(hint: String): MutableList<AutofillFieldMetadata>? {
+        return autofillHintsToFieldsMap[hint]
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.kt
new file mode 100644
index 0000000..dc62d12
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.kt
@@ -0,0 +1,119 @@
+/*
+ * 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.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.View
+import android.widget.RemoteViews
+import com.example.android.autofillframework.CommonUtil.TAG
+import com.example.android.autofillframework.R
+import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection
+import java.util.HashMap
+
+
+/**
+ * This is a class containing helper methods for building Autofill Datasets and Responses.
+ */
+object AutofillHelper {
+
+    /**
+     * Wraps autofill data in a [Dataset] object which can then be sent back to the
+     * client View.
+     */
+    fun newDataset(context: Context, autofillFieldMetadata: AutofillFieldMetadataCollection,
+            filledAutofillFieldCollection: FilledAutofillFieldCollection,
+            datasetAuth: Boolean): Dataset? {
+        filledAutofillFieldCollection.datasetName?.let { datasetName ->
+            val datasetBuilder: Dataset.Builder
+            if (datasetAuth) {
+                datasetBuilder = Dataset.Builder(newRemoteViews(context.packageName, datasetName,
+                        R.drawable.ic_lock_black_24dp))
+                val sender = AuthActivity.getAuthIntentSenderForDataset(context, datasetName)
+                datasetBuilder.setAuthentication(sender)
+            } else {
+                datasetBuilder = Dataset.Builder(newRemoteViews(context.packageName, datasetName,
+                        R.drawable.ic_person_black_24dp))
+            }
+            val setValueAtLeastOnce = filledAutofillFieldCollection
+                    .applyToFields(autofillFieldMetadata, datasetBuilder)
+            if (setValueAtLeastOnce) {
+                return datasetBuilder.build()
+            }
+        }
+        return null
+    }
+
+    fun newRemoteViews(packageName: String, remoteViewsText: String,
+            @DrawableRes drawableId: Int): RemoteViews {
+        val presentation = 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 [FillResponse] object (essentially a series of Datasets) which can
+     * then be sent back to the client View.
+     */
+    fun newResponse(context: Context,
+            datasetAuth: Boolean, autofillFieldMetadata: AutofillFieldMetadataCollection,
+            filledAutofillFieldCollectionMap: HashMap<String, FilledAutofillFieldCollection>?): FillResponse? {
+        val responseBuilder = FillResponse.Builder()
+        filledAutofillFieldCollectionMap?.keys?.let { datasetNames ->
+            for (datasetName in datasetNames) {
+                filledAutofillFieldCollectionMap[datasetName]?.let { clientFormData ->
+                    val dataset = newDataset(context, autofillFieldMetadata, clientFormData, datasetAuth)
+                    dataset?.let(responseBuilder::addDataset)
+                }
+            }
+        }
+        if (autofillFieldMetadata.saveType != 0) {
+            val autofillIds = autofillFieldMetadata.autofillIds
+            responseBuilder.setSaveInfo(SaveInfo.Builder(autofillFieldMetadata.saveType,
+                    autofillIds.toTypedArray()).build())
+            return responseBuilder.build()
+        } else {
+            Log.d(TAG, "These fields are not meant to be saved by autofill.")
+            return null
+        }
+    }
+
+    fun isValidHint(hint: String): Boolean {
+        when (hint) {
+            View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE,
+            View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY,
+            View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
+            View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR,
+            View.AUTOFILL_HINT_CREDIT_CARD_NUMBER,
+            View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE,
+            View.AUTOFILL_HINT_EMAIL_ADDRESS,
+            View.AUTOFILL_HINT_PHONE,
+            View.AUTOFILL_HINT_NAME,
+            View.AUTOFILL_HINT_PASSWORD,
+            View.AUTOFILL_HINT_POSTAL_ADDRESS,
+            View.AUTOFILL_HINT_POSTAL_CODE,
+            View.AUTOFILL_HINT_USERNAME ->
+                return true
+            else ->
+                return false
+        }
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.kt
new file mode 100644
index 0000000..704d17a
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/MyAutofillService.kt
@@ -0,0 +1,97 @@
+/*
+ * 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.os.CancellationSignal
+import android.service.autofill.AutofillService
+import android.service.autofill.FillCallback
+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.widget.Toast
+import com.example.android.autofillframework.CommonUtil.TAG
+import com.example.android.autofillframework.CommonUtil.bundleToString
+import com.example.android.autofillframework.R
+import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsAutofillRepository
+import com.example.android.autofillframework.multidatasetservice.settings.MyPreferences
+
+class MyAutofillService : AutofillService() {
+
+    override fun onFillRequest(request: FillRequest, cancellationSignal: CancellationSignal,
+            callback: FillCallback) {
+        val structure = request.fillContexts[request.fillContexts.size - 1].structure
+        val packageName = structure.activityComponent.packageName
+        if (!PackageVerifier.isValidPackage(applicationContext, packageName)) {
+            Toast.makeText(applicationContext, R.string.invalid_package_signature,
+                    Toast.LENGTH_SHORT).show()
+            return
+        }
+        val data = request.clientState
+        Log.d(TAG, "onFillRequest(): data=" + bundleToString(data))
+        cancellationSignal.setOnCancelListener { Log.w(TAG, "Cancel autofill not implemented in this sample.") }
+        // Parse AutoFill data in Activity
+        val parser = StructureParser(structure)
+        parser.parseForFill()
+        val autofillFields = parser.autofillFields
+
+        val responseBuilder = FillResponse.Builder()
+        // Check user's settings for authenticating Responses and Datasets.
+        val responseAuth = MyPreferences.isResponseAuth(this)
+        if (responseAuth && autofillFields.autofillIds.size > 0) {
+            // If the entire Autofill Response is authenticated, AuthActivity is used
+            // to generate Response.
+            val sender = AuthActivity.getAuthIntentSenderForResponse(this)
+            val presentation = AutofillHelper
+                    .newRemoteViews(packageName, getString(R.string.autofill_sign_in_prompt), R.drawable.ic_lock_black_24dp)
+            responseBuilder
+                    .setAuthentication(autofillFields.autofillIds.toTypedArray(), sender, presentation)
+            callback.onSuccess(responseBuilder.build())
+        } else {
+            val datasetAuth = MyPreferences.isDatasetAuth(this)
+            val clientFormDataMap = SharedPrefsAutofillRepository.getFilledAutofillFieldCollection(this,
+                    autofillFields.focusedAutofillHints, autofillFields.allAutofillHints)
+            val response = AutofillHelper.newResponse(this, datasetAuth, autofillFields, clientFormDataMap)
+            callback.onSuccess(response)
+        }
+    }
+
+    override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
+        val context = request.fillContexts
+        val structure = context[context.size - 1].structure
+        val packageName = structure.activityComponent.packageName
+        if (!PackageVerifier.isValidPackage(applicationContext, packageName)) {
+            Toast.makeText(applicationContext, R.string.invalid_package_signature,
+                    Toast.LENGTH_SHORT).show()
+            return
+        }
+        val data = request.clientState
+        Log.d(TAG, "onSaveRequest(): data=" + bundleToString(data))
+        val parser = StructureParser(structure)
+        parser.parseForSave()
+        SharedPrefsAutofillRepository.saveFilledAutofillFieldCollection(this,
+                parser.filledAutofillFieldCollection)
+    }
+
+    override fun onConnected() {
+        Log.d(TAG, "onConnected")
+    }
+
+    override fun onDisconnected() {
+        Log.d(TAG, "onDisconnected")
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/PackageVerifier.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/PackageVerifier.kt
new file mode 100644
index 0000000..d059a23
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/PackageVerifier.kt
@@ -0,0 +1,98 @@
+package com.example.android.autofillframework.multidatasetservice
+
+/*
+ * 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.
+ */
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.util.Log
+import com.example.android.autofillframework.CommonUtil.TAG
+import java.io.ByteArrayInputStream
+import java.security.MessageDigest
+import java.security.cert.CertificateFactory
+import java.security.cert.X509Certificate
+
+object PackageVerifier {
+
+
+    /**
+     * Verifies if a package is valid by matching its certificate with the previously stored
+     * certificate.
+     */
+    fun isValidPackage(context: Context, packageName: String): Boolean {
+        val hash: String
+        try {
+            hash = getCertificateHash(context, packageName)
+            Log.d(TAG, "Hash for $packageName: $hash")
+        } catch (e: Exception) {
+            Log.w(TAG, "Error getting hash for $packageName: $e")
+            return false
+        }
+
+        return verifyHash(context, packageName, hash)
+    }
+
+    private fun getCertificateHash(context: Context, packageName: String): String {
+        val pm = context.packageManager
+        val packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
+        val signatures = packageInfo.signatures
+        val cert = signatures[0].toByteArray()
+        ByteArrayInputStream(cert).use { input ->
+            val factory = CertificateFactory.getInstance("X509")
+            val x509 = factory.generateCertificate(input) as X509Certificate
+            val md = MessageDigest.getInstance("SHA256")
+            val publicKey = md.digest(x509.encoded)
+            return toHexFormat(publicKey)
+        }
+    }
+
+    private fun toHexFormat(bytes: ByteArray): String {
+        val builder = StringBuilder(bytes.size * 2)
+        for (i in bytes.indices) {
+            var hex = Integer.toHexString(bytes[i].toInt())
+            val 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.size - 1) {
+                builder.append(':')
+            }
+        }
+        return builder.toString()
+    }
+
+    private fun verifyHash(context: Context, packageName: String, hash: String): Boolean {
+        val prefs = context.applicationContext.getSharedPreferences(
+                "package-hashes", Context.MODE_PRIVATE)
+        if (!prefs.contains(packageName)) {
+            Log.d(TAG, "Creating intial hash for " + packageName)
+            prefs.edit().putString(packageName, hash).apply()
+            return true
+        }
+
+        val existingHash = prefs.getString(packageName, null)
+        if (hash != existingHash) {
+            Log.w(TAG, "hash mismatch for " + packageName + ": expected " + existingHash
+                    + ", got " + hash)
+            return false
+        }
+        return true
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.kt
new file mode 100644
index 0000000..e504210
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.util.Log
+import com.example.android.autofillframework.CommonUtil.TAG
+import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField
+import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection
+
+/**
+ * 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.
+ */
+internal class StructureParser(private val autofillStructure: AssistStructure) {
+    val autofillFields = AutofillFieldMetadataCollection()
+    var filledAutofillFieldCollection: FilledAutofillFieldCollection = FilledAutofillFieldCollection()
+        private set
+
+    fun parseForFill() {
+        parse(true)
+    }
+
+    fun parseForSave() {
+        parse(false)
+    }
+
+    /**
+     * Traverse AssistStructure and add ViewNode metadata to a flat list.
+     */
+    private fun parse(forFill: Boolean) {
+        Log.d(TAG, "Parsing structure for " + autofillStructure.activityComponent)
+        val nodes = autofillStructure.windowNodeCount
+        filledAutofillFieldCollection = FilledAutofillFieldCollection()
+        for (i in 0 until nodes) {
+            parseLocked(forFill, autofillStructure.getWindowNodeAt(i).rootViewNode)
+        }
+    }
+
+    private fun parseLocked(forFill: Boolean, viewNode: ViewNode) {
+        viewNode.autofillHints?.let { autofillHints ->
+            if (autofillHints.isNotEmpty()) {
+                if (forFill) {
+                    autofillFields.add(AutofillFieldMetadata(viewNode))
+                } else {
+                    filledAutofillFieldCollection.add(FilledAutofillField(viewNode))
+                }
+            }
+        }
+        val childrenSize = viewNode.childCount
+        for (i in 0 until childrenSize) {
+            parseLocked(forFill, viewNode.getChildAt(i))
+
+        }
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillRepository.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillRepository.kt
new file mode 100644
index 0000000..4cb5ab8
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillRepository.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.example.android.autofillframework.multidatasetservice.datasource
+
+import android.content.Context
+import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection
+import java.util.HashMap
+
+interface AutofillRepository {
+
+    /**
+     * Gets saved FilledAutofillFieldCollection that contains some objects that can autofill fields with these
+     * `autofillHints`.
+     */
+    fun getFilledAutofillFieldCollection(context: Context, focusedAutofillHints: List<String>,
+            allAutofillHints: List<String>): HashMap<String, FilledAutofillFieldCollection>?
+
+    /**
+     * Saves LoginCredential under this datasetName.
+     */
+    fun saveFilledAutofillFieldCollection(context: Context,
+            filledAutofillFieldCollection: FilledAutofillFieldCollection)
+
+    /**
+     * Clears all data.
+     */
+    fun clear(context: Context)
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.kt
new file mode 100644
index 0000000..1006124
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.ArraySet
+import com.example.android.autofillframework.CommonUtil
+import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection
+import com.google.gson.GsonBuilder
+import com.google.gson.reflect.TypeToken
+
+
+/**
+ * Singleton autofill data repository that stores autofill fields to SharedPreferences.
+ * Disclaimer: you should not store sensitive fields like user data unencrypted. This is done
+ * here only for simplicity and learning purposes.
+ */
+object SharedPrefsAutofillRepository : AutofillRepository {
+    private val SHARED_PREF_KEY = "com.example.android.autofillframework.service"
+    private val CLIENT_FORM_DATA_KEY = "loginCredentialDatasets"
+    private val DATASET_NUMBER_KEY = "datasetNumber"
+
+    private fun getPrefs(context: Context): SharedPreferences {
+        return context.applicationContext.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
+    }
+
+    override fun getFilledAutofillFieldCollection(context: Context, focusedAutofillHints: List<String>,
+            allAutofillHints: List<String>): HashMap<String, FilledAutofillFieldCollection>? {
+        var hasDataForFocusedAutofillHints = false
+        val clientFormDataMap = HashMap<String, FilledAutofillFieldCollection>()
+        val clientFormDataStringSet = getAllAutofillDataStringSet(context)
+        val gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().setPrettyPrinting().create()
+        val type = object : TypeToken<FilledAutofillFieldCollection>() {}.type
+        for (clientFormDataString in clientFormDataStringSet) {
+            gson.fromJson<FilledAutofillFieldCollection>(clientFormDataString, type)?.let {
+                if (it.helpsWithHints(focusedAutofillHints)) {
+                    // Saved data has data relevant to at least 1 of the hints associated with the
+                    // View in focus.
+                    hasDataForFocusedAutofillHints = true
+                    it.datasetName?.let { datasetName ->
+                        if (it.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(datasetName, it)
+                        }
+                    }
+                }
+            }
+        }
+        if (hasDataForFocusedAutofillHints) {
+            return clientFormDataMap
+        } else {
+            return null
+        }
+    }
+
+    override fun saveFilledAutofillFieldCollection(context: Context, filledAutofillFieldCollection: FilledAutofillFieldCollection) {
+        val datasetName = "dataset-" + getDatasetNumber(context)
+        filledAutofillFieldCollection.datasetName = datasetName
+        val allAutofillData = getAllAutofillDataStringSet(context)
+        val gson = CommonUtil.createGson()
+        allAutofillData.add(gson.toJson(filledAutofillFieldCollection).toString())
+        saveAllAutofillDataStringSet(context, allAutofillData)
+        incrementDatasetNumber(context)
+    }
+
+    override fun clear(context: Context) {
+        getPrefs(context).edit().remove(CLIENT_FORM_DATA_KEY).remove(DATASET_NUMBER_KEY).apply()
+    }
+
+    private fun getAllAutofillDataStringSet(context: Context): MutableSet<String> {
+        return getPrefs(context).getStringSet(CLIENT_FORM_DATA_KEY, ArraySet<String>())
+    }
+
+    private fun saveAllAutofillDataStringSet(context: Context,
+            allAutofillDataStringSet: Set<String>) {
+        getPrefs(context).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 fun getDatasetNumber(context: Context): Int {
+        return getPrefs(context).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 fun incrementDatasetNumber(context: Context) {
+        getPrefs(context).edit().putInt(DATASET_NUMBER_KEY, getDatasetNumber(context) + 1).apply()
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.kt
new file mode 100644
index 0000000..7421cbc
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.app.assist.AssistStructure
+import android.view.autofill.AutofillValue
+import com.example.android.autofillframework.multidatasetservice.AutofillHelper
+import com.google.gson.annotations.Expose
+
+/**
+ * JSON serializable data class containing the same data as an [AutofillValue].
+ */
+class FilledAutofillField(viewNode: AssistStructure.ViewNode) {
+    @Expose
+    var textValue: String? = null
+
+    @Expose
+    var dateValue: Long? = null
+
+    @Expose
+    var toggleValue: Boolean? = null
+
+    val autofillHints = viewNode.autofillHints.filter(AutofillHelper::isValidHint).toTypedArray()
+
+    init {
+        viewNode.autofillValue?.let {
+            if (it.isList) {
+                val index = it.listValue
+                viewNode.autofillOptions?.let { autofillOptions ->
+                    if (autofillOptions.size > index) {
+                        textValue = autofillOptions[index].toString()
+                    }
+                }
+            } else if (it.isDate) {
+                dateValue = it.dateValue
+            } else if (it.isText) {
+                // Using toString of AutofillValue.getTextValue in order to save it to
+                // SharedPreferences.
+                textValue = it.textValue.toString()
+            } else {
+            }
+        }
+    }
+
+    fun isNull(): Boolean {
+        return textValue == null && dateValue == null && toggleValue == null
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.kt
new file mode 100644
index 0000000..cef2918
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.kt
@@ -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.autofillframework.multidatasetservice.model
+
+import android.service.autofill.Dataset
+import android.util.Log
+import android.view.View
+import android.view.autofill.AutofillId
+import android.view.autofill.AutofillValue
+import com.example.android.autofillframework.CommonUtil.TAG
+import com.example.android.autofillframework.multidatasetservice.AutofillFieldMetadataCollection
+import com.google.gson.annotations.Expose
+import java.util.HashMap
+
+
+/**
+ * FilledAutofillFieldCollection is the model that represents all of the form data on a client app's page, plus the
+ * dataset name associated with it.
+ */
+class FilledAutofillFieldCollection @JvmOverloads constructor(
+        @Expose var datasetName: String? = null,
+        @Expose private val hintMap: HashMap<String, FilledAutofillField> = HashMap<String,
+                FilledAutofillField>()
+) {
+
+    /**
+     * Sets values for a list of autofillHints.
+     */
+    fun add(autofillField: FilledAutofillField) {
+        autofillField.autofillHints.forEach { autofillHint ->
+            hintMap[autofillHint] = autofillField
+        }
+    }
+
+    /**
+     * Populates a [Dataset.Builder] with appropriate values for each [AutofillId]
+     * in a `AutofillFieldMetadataCollection`. In other words, it builds an Autofill dataset
+     * by applying saved values (from this `FilledAutofillFieldCollection`) to Views specified
+     * in a `AutofillFieldMetadataCollection`, which represents the current page the user is
+     * on.
+     */
+    fun applyToFields(autofillFieldMetadataCollection: AutofillFieldMetadataCollection,
+            datasetBuilder: Dataset.Builder): Boolean {
+        var setValueAtLeastOnce = false
+        for (hint in autofillFieldMetadataCollection.allAutofillHints) {
+            val autofillFields = autofillFieldMetadataCollection.getFieldsForHint(hint) ?: continue
+            for (autofillField in autofillFields) {
+                val autofillId = autofillField.autofillId
+                val autofillType = autofillField.autofillType
+                val savedAutofillValue = hintMap[hint]
+                when (autofillType) {
+                    View.AUTOFILL_TYPE_LIST -> {
+                        savedAutofillValue?.textValue?.let {
+                            val index = autofillField.getAutofillOptionIndex(it)
+                            if (index != -1) {
+                                datasetBuilder.setValue(autofillId, AutofillValue.forList(index))
+                                setValueAtLeastOnce = true
+                            }
+                        }
+                    }
+                    View.AUTOFILL_TYPE_DATE -> {
+                        savedAutofillValue?.dateValue?.let { date ->
+                            datasetBuilder.setValue(autofillId, AutofillValue.forDate(date))
+                            setValueAtLeastOnce = true
+                        }
+                    }
+                    View.AUTOFILL_TYPE_TEXT -> {
+                        savedAutofillValue?.textValue?.let { text ->
+                            datasetBuilder.setValue(autofillId, AutofillValue.forText(text))
+                            setValueAtLeastOnce = true
+                        }
+                    }
+                    View.AUTOFILL_TYPE_TOGGLE -> {
+                        savedAutofillValue?.toggleValue?.let { toggle ->
+                            datasetBuilder.setValue(autofillId, AutofillValue.forToggle(toggle))
+                            setValueAtLeastOnce = true
+                        }
+                    }
+                    else -> Log.w(TAG, "Invalid autofill type - " + autofillType)
+                }
+            }
+        }
+        return setValueAtLeastOnce
+    }
+
+    /**
+     * @param autofillHints List of autofill hints, usually associated with a View or set of Views.
+     * @return whether any of the filled fields on the page have at least 1 autofillHint that is
+     * in the provided autofillHints.
+     */
+    fun helpsWithHints(autofillHints: List<String>): Boolean {
+        for (autofillHint in autofillHints) {
+            hintMap[autofillHint]?.let { savedAutofillValue ->
+                if (!savedAutofillValue.isNull()) {
+                    return true
+                }
+            }
+        }
+        return false
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/MyPreferences.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/MyPreferences.kt
new file mode 100644
index 0000000..1ddf3da
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/MyPreferences.kt
@@ -0,0 +1,77 @@
+/*
+ * 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
+
+object MyPreferences {
+    private val TAG = "MyPreferences"
+
+    private val SHARED_PREF_KEY = "com.example.android.autofillframework.service.settings.MyPreferences"
+    private val RESPONSE_AUTH_KEY = "response_auth"
+    private val DATASET_AUTH_KEY = "dataset_auth"
+    private val MASTER_PASSWORD_KEY = "master_password"
+
+    private fun getPrefs(context: Context): SharedPreferences {
+        return context.applicationContext.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
+    }
+
+    /**
+     * Determines whether [FillResponse]s should require authentication.
+     */
+    fun isResponseAuth(context: Context): Boolean {
+        return getPrefs(context).getBoolean(RESPONSE_AUTH_KEY, false)
+    }
+
+    fun setResponseAuth(context: Context, responseAuth: Boolean) {
+        getPrefs(context).edit().putBoolean(RESPONSE_AUTH_KEY, responseAuth).apply()
+    }
+
+    /**
+     * Determines whether [Dataset]s should require authentication.
+     */
+    fun isDatasetAuth(context: Context): Boolean {
+        return getPrefs(context).getBoolean(DATASET_AUTH_KEY, false)
+    }
+
+    fun setDatasetAuth(context: Context, datasetAuth: Boolean) {
+        getPrefs(context).edit().putBoolean(DATASET_AUTH_KEY, datasetAuth).apply()
+    }
+
+    /**
+     * Gets autofill master password.
+     */
+    fun getMasterPassword(context: Context): String? {
+        return getPrefs(context).getString(MASTER_PASSWORD_KEY, null)
+    }
+
+    /**
+     * Sets autofill master password.
+     */
+    fun setMasterPassword(context: Context, masterPassword: String) {
+        getPrefs(context).edit().putString(MASTER_PASSWORD_KEY, masterPassword).apply()
+    }
+
+    /**
+     * Removes master password.
+     */
+    fun clearCredentials(context: Context) {
+        getPrefs(context).edit().remove(MASTER_PASSWORD_KEY).apply()
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.kt b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.kt
new file mode 100644
index 0000000..c24a0e9
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.kt
@@ -0,0 +1,151 @@
+/*
+ * 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.os.Bundle
+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.widget.CompoundButton
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.Switch
+import android.widget.TextView
+import com.example.android.autofillframework.R
+import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsAutofillRepository
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_auth_credentials_container
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_auth_credentials_icon
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_auth_credentials_label
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_auth_datasets_container
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_auth_datasets_label
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_auth_datasets_switch
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_auth_responses_container
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_auth_responses_label
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_auth_responses_switch
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_clear_data_container
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_clear_data_icon
+import kotlinx.android.synthetic.main.multidataset_service_settings_activity.settings_clear_data_label
+
+class SettingsActivity : AppCompatActivity() {
+
+    public override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        setContentView(R.layout.multidataset_service_settings_activity)
+        setupSettingsSwitch(settings_auth_responses_container,
+                settings_auth_responses_label,
+                settings_auth_responses_switch,
+                MyPreferences.isResponseAuth(this),
+                CompoundButton.OnCheckedChangeListener { compoundButton, b ->
+                    MyPreferences.setResponseAuth(this@SettingsActivity, b)
+                })
+        setupSettingsSwitch(settings_auth_datasets_container,
+                settings_auth_datasets_label,
+                settings_auth_datasets_switch,
+                MyPreferences.isDatasetAuth(this),
+                CompoundButton.OnCheckedChangeListener { compoundButton, b ->
+                    MyPreferences.setDatasetAuth(this@SettingsActivity, b)
+                })
+        setupSettingsButton(settings_clear_data_container,
+                settings_clear_data_label,
+                settings_clear_data_icon,
+                View.OnClickListener { buildClearDataDialog().show() })
+
+        setupSettingsButton(settings_auth_credentials_container,
+                settings_auth_credentials_label,
+                settings_auth_credentials_icon,
+                View.OnClickListener {
+                    if (MyPreferences.getMasterPassword(this@SettingsActivity) != null) {
+                        buildCurrentCredentialsDialog().show()
+                    } else {
+                        buildNewCredentialsDialog().show()
+                    }
+                })
+    }
+
+    private fun buildClearDataDialog(): AlertDialog {
+        return AlertDialog.Builder(this@SettingsActivity)
+                .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.clear(this@SettingsActivity)
+                    MyPreferences.clearCredentials(this@SettingsActivity)
+                    dialog.dismiss()
+                }
+                .create()
+    }
+
+    private fun prepareCredentialsDialog(): AlertDialog.Builder {
+        return AlertDialog.Builder(this@SettingsActivity)
+                .setTitle(R.string.settings_auth_change_credentials_title)
+                .setNegativeButton(R.string.cancel, null)
+    }
+
+    private fun buildCurrentCredentialsDialog(): AlertDialog {
+        val currentPasswordField = LayoutInflater
+                .from(this@SettingsActivity)
+                .inflate(R.layout.multidataset_service_settings_authentication_dialog, null)
+                .findViewById<EditText>(R.id.master_password_field)
+        return prepareCredentialsDialog()
+                .setMessage(R.string.settings_auth_enter_current_password)
+                .setView(currentPasswordField)
+                .setPositiveButton(R.string.ok) { dialog, which ->
+                    val password = currentPasswordField.text.toString()
+                    if (MyPreferences.getMasterPassword(this@SettingsActivity) == password) {
+                        buildNewCredentialsDialog().show()
+                        dialog.dismiss()
+                    }
+                }
+                .create()
+    }
+
+    private fun buildNewCredentialsDialog(): AlertDialog {
+        val newPasswordField = LayoutInflater
+                .from(this@SettingsActivity)
+                .inflate(R.layout.multidataset_service_settings_authentication_dialog, null)
+                .findViewById<EditText>(R.id.master_password_field)
+        return prepareCredentialsDialog()
+                .setMessage(R.string.settings_auth_enter_new_password)
+                .setView(newPasswordField)
+                .setPositiveButton(R.string.ok) { dialog, which ->
+                    val password = newPasswordField.text.toString()
+                    MyPreferences.setMasterPassword(this@SettingsActivity, password)
+                    dialog.dismiss()
+                }
+                .create()
+    }
+
+    private fun setupSettingsSwitch(container: ViewGroup, switchLabelView: TextView, switchView: Switch, checked: Boolean,
+            checkedChangeListener: CompoundButton.OnCheckedChangeListener) {
+        val switchLabel = switchLabelView.text.toString()
+        with(switchView) {
+            contentDescription = switchLabel
+            isChecked = checked
+            setOnCheckedChangeListener(checkedChangeListener)
+        }
+        container.setOnClickListener { switchView.performClick() }
+    }
+
+    private fun setupSettingsButton(container: ViewGroup, buttonLabelView: TextView, imageView: ImageView,
+            onClickListener: View.OnClickListener) {
+        val buttonLabel = buttonLabelView.text.toString()
+        imageView.contentDescription = buttonLabel
+        container.setOnClickListener(onClickListener)
+    }
+}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java
deleted file mode 100644
index 768b2ee..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java
+++ /dev/null
@@ -1,160 +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.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.os.Bundle;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.support.annotation.Nullable;
-import android.text.Editable;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.datasource.LocalAutofillRepository;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-import com.example.android.autofillframework.service.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 Activity {
-
-    // Unique id for dataset intents.
-    private static int sDatasetPendingIntentId = 0;
-
-    private EditText mMasterPassword;
-    private Button mCancel;
-    private Button mLogin;
-    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.auth_activity);
-        mCancel = findViewById(R.id.cancel);
-        mLogin = findViewById(R.id.login);
-        mMasterPassword = findViewById(R.id.master_password);
-        mLogin.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                login();
-            }
-
-        });
-
-        mCancel.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(structure);
-        parser.parse();
-        AutofillFieldsCollection autofillFields = parser.getAutofillFields();
-        int saveTypes = parser.getSaveTypes();
-        mReplyIntent = new Intent();
-        HashMap<String, ClientFormData> clientFormDataMap =
-                LocalAutofillRepository.getInstance(this).getClientFormData
-                        (autofillFields.getFocusedHints(), autofillFields.getAllHints());
-        if (forResponse) {
-            setResponseIntent(AutofillHelper.newResponse
-                    (this, false, autofillFields, saveTypes, clientFormDataMap));
-        } else {
-            String datasetName = intent.getStringExtra(EXTRA_DATASET_NAME);
-            setDatasetIntent(AutofillHelper.newDataset
-                    (this, autofillFields, clientFormDataMap.get(datasetName)));
-        }
-    }
-
-    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/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java
deleted file mode 100644
index 460729e..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java
+++ /dev/null
@@ -1,100 +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.service;
-
-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.util.Log;
-import android.view.autofill.AutofillId;
-import android.widget.RemoteViews;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-
-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 {
-
-    /**
-     * Wraps autofill data in a LoginCredential  Dataset object which can then be sent back to the
-     * client View.
-     */
-    public static Dataset newDataset(Context context,
-            AutofillFieldsCollection autofillFields, ClientFormData clientFormData) {
-        Dataset.Builder datasetBuilder = new Dataset.Builder
-                (newRemoteViews(context.getPackageName(), clientFormData.getDatasetName()));
-        boolean setValueAtLeastOnce = clientFormData.applyToFields(autofillFields, datasetBuilder);
-        if (setValueAtLeastOnce) {
-            return datasetBuilder.build();
-        } else {
-            return null;
-        }
-    }
-
-    public static RemoteViews newRemoteViews(String packageName, String remoteViewsText) {
-        RemoteViews presentation = new RemoteViews(packageName, R.layout.list_item);
-        presentation.setTextViewText(R.id.text1, remoteViewsText);
-        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, AutofillFieldsCollection autofillFields, int saveType,
-            HashMap<String, ClientFormData> clientFormDataMap) {
-        FillResponse.Builder responseBuilder = new FillResponse.Builder();
-        if (clientFormDataMap != null) {
-            Set<String> datasetNames = clientFormDataMap.keySet();
-            for (String datasetName : datasetNames) {
-                ClientFormData clientFormData = clientFormDataMap.get(datasetName);
-                if (datasetAuth) {
-                    Dataset.Builder datasetBuilder =
-                            new Dataset.Builder(newRemoteViews
-                                    (context.getPackageName(), clientFormData.getDatasetName()));
-                    IntentSender sender = AuthActivity
-                            .getAuthIntentSenderForDataset(context, clientFormData.getDatasetName());
-                    datasetBuilder.setAuthentication(sender);
-                    responseBuilder.addDataset(datasetBuilder.build());
-                } else {
-                    Dataset dataset = newDataset(context, autofillFields, clientFormData);
-                    if (dataset != null) {
-                        responseBuilder.addDataset(dataset);
-                    }
-                }
-            }
-        }
-        if (saveType != 0) {
-            AutofillId[] autofillIds = autofillFields.getAutofillIds();
-            responseBuilder.setSaveInfo(new SaveInfo.Builder(saveType, autofillIds).build());
-            return responseBuilder.build();
-        } else {
-            Log.d(TAG, "These fields are not meant to be saved by autofill.");
-            return null;
-        }
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java
deleted file mode 100644
index 61e4205..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java
+++ /dev/null
@@ -1,128 +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.service;
-
-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.widget.RemoteViews;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.datasource.LocalAutofillRepository;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-import com.example.android.autofillframework.service.settings.MyPreferences;
-
-import java.util.HashMap;
-import java.util.List;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-import static com.example.android.autofillframework.CommonUtil.bundleToString;
-
-public class MyAutofillService extends AutofillService {
-
-    @Override
-    public void onFillRequest(AssistStructure assistStructure, Bundle bundle, int i,
-            CancellationSignal cancellationSignal, FillCallback fillCallback) {
-        /* Deprecated, ignore */
-    }
-
-    @Override
-    public void onSaveRequest(AssistStructure assistStructure, Bundle bundle,
-            SaveCallback saveCallback) {
-        /* Deprecated, ignore */
-    }
-
-    @Override
-    public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
-            FillCallback callback) {
-        AssistStructure structure = request.getStructure();
-        final Bundle data = request.getClientState();
-        Log.d(TAG, "onFillRequest(): data=" + bundleToString(data));
-
-        // Temporary hack for disabling autofill for components in this autofill service.
-        // i.e. we don't want to autofill components in AuthActivity.
-        if (structure.getActivityComponent().toShortString()
-                .contains("com.example.android.autofillframework.service")) {
-            callback.onSuccess(null);
-            return;
-        }
-        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(structure);
-        parser.parse();
-        AutofillFieldsCollection autofillFields = parser.getAutofillFields();
-        int saveTypes = parser.getSaveTypes();
-
-        FillResponse.Builder responseBuilder = new FillResponse.Builder();
-        // Check user's settings for authenticating Responses and Datasets.
-        boolean responseAuth = MyPreferences.getInstance(this).isResponseAuth();
-        if (responseAuth) {
-            // 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));
-            responseBuilder
-                    .setAuthentication(autofillFields.getAutofillIds(), sender, presentation);
-            callback.onSuccess(responseBuilder.build());
-        } else {
-            boolean datasetAuth = MyPreferences.getInstance(this).isDatasetAuth();
-            HashMap<String, ClientFormData> clientFormDataMap =
-                    LocalAutofillRepository.getInstance(this).getClientFormData
-                            (autofillFields.getFocusedHints(), autofillFields.getAllHints());
-            FillResponse response = AutofillHelper.newResponse
-                    (this, datasetAuth, autofillFields, saveTypes, 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();
-        final Bundle data = request.getClientState();
-        Log.d(TAG, "onSaveRequest(): data=" + bundleToString(data));
-        StructureParser parser = new StructureParser(structure);
-        parser.parse();
-        ClientFormData clientFormData = parser.getClientFormData();
-        LocalAutofillRepository.getInstance(this).saveClientFormData(clientFormData);
-    }
-
-    @Override
-    public void onConnected() {
-        Log.d(TAG, "onConnected");
-    }
-
-    @Override
-    public void onDisconnected() {
-        Log.d(TAG, "onDisconnected");
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.java
deleted file mode 100644
index b629444..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.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.service;
-
-import android.app.assist.AssistStructure;
-import android.app.assist.AssistStructure.ViewNode;
-import android.app.assist.AssistStructure.WindowNode;
-import android.util.Log;
-
-import com.example.android.autofillframework.service.model.AutofillField;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-import com.example.android.autofillframework.service.model.SavedAutofillValue;
-
-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 records
- */
-final class StructureParser {
-    private final AutofillFieldsCollection mAutofillFields = new AutofillFieldsCollection();
-    private final AssistStructure mStructure;
-    private ClientFormData mClientFormData;
-
-    StructureParser(AssistStructure structure) {
-        mStructure = structure;
-
-    }
-
-    /**
-     * Traverse AssistStructure and add ViewNode metadata to a flat list.
-     */
-    void parse() {
-        Log.d(TAG, "Parsing structure for " + mStructure.getActivityComponent());
-        int nodes = mStructure.getWindowNodeCount();
-        mClientFormData = new ClientFormData();
-        for (int i = 0; i < nodes; i++) {
-            WindowNode node = mStructure.getWindowNodeAt(i);
-            ViewNode view = node.getRootViewNode();
-            parseLocked(view);
-        }
-    }
-
-    private void parseLocked(ViewNode viewNode) {
-        if (viewNode.getAutofillHints() != null && viewNode.getAutofillHints().length > 0) {
-            //TODO check to make sure hints are supported by service.
-            mAutofillFields.add(new AutofillField(viewNode));
-            mClientFormData
-                    .set(viewNode.getAutofillHints(), SavedAutofillValue.fromViewNode(viewNode));
-        }
-        int childrenSize = viewNode.getChildCount();
-        if (childrenSize > 0) {
-            for (int i = 0; i < childrenSize; i++) {
-                parseLocked(viewNode.getChildAt(i));
-            }
-        }
-    }
-
-    public AutofillFieldsCollection getAutofillFields() {
-        return mAutofillFields;
-    }
-
-    public int getSaveTypes() {
-        return mAutofillFields.getSaveType();
-    }
-
-    public ClientFormData getClientFormData() {
-        return mClientFormData;
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.java
deleted file mode 100644
index 8de8b64..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.java
+++ /dev/null
@@ -1,41 +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.service.datasource;
-
-import com.example.android.autofillframework.service.model.ClientFormData;
-
-import java.util.HashMap;
-import java.util.List;
-
-public interface AutofillRepository {
-
-    /**
-     * Gets saved ClientFormData that contains some objects that can autofill fields with these
-     * {@code autofillHints}.
-     */
-    HashMap<String, ClientFormData> getClientFormData(List<String> focusedAutofillHints,
-            List<String> allAutofillHints);
-
-    /**
-     * Saves LoginCredential under this datasetName.
-     */
-    void saveClientFormData(ClientFormData clientFormData);
-
-    /**
-     * Clears all data.
-     */
-    void clear();
-}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java
deleted file mode 100644
index 8336fe1..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java
+++ /dev/null
@@ -1,127 +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.service.datasource;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.ArraySet;
-
-import com.example.android.autofillframework.service.model.ClientFormData;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Singleton autofill data repository, that stores autofill fields to SharedPreferences.
- * DISCLAIMER, you should not store sensitive fields like user data unencrypted. This is only done
- * here for simplicity and learning purposes.
- */
-public class LocalAutofillRepository implements AutofillRepository {
-    private static final String SHARED_PREF_KEY = "com.example.android.autofillframework.service";
-    private static final String CLIENT_FORM_DATA_KEY = "loginCredentialDatasets";
-    private static final String DATASET_NUMBER_KEY = "datasetNumber";
-
-    private static LocalAutofillRepository sInstance;
-
-    private final SharedPreferences mPrefs;
-
-    // TODO prepend with autofill data set in Settings.
-    private LocalAutofillRepository(Context context) {
-        mPrefs = context.getApplicationContext()
-                .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE);
-    }
-
-    public static LocalAutofillRepository getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new LocalAutofillRepository(context);
-        }
-        return sInstance;
-    }
-
-    @Override
-    public HashMap<String, ClientFormData> getClientFormData(List<String> focusedAutofillHints,
-            List<String> allAutofillHints) {
-        try {
-            // TODO use sqlite instead.
-            boolean hasDataForFocusedAutofillHints = false;
-            HashMap<String, ClientFormData> clientFormDataMap = new HashMap<>();
-            Set<String> clientFormDataStringSet = getAllAutofillDataStringSet();
-            for (String clientFormDataString : clientFormDataStringSet) {
-                ClientFormData clientFormData = ClientFormData
-                        .fromJson(new JSONObject(clientFormDataString));
-                if (clientFormData != null) {
-                    if (clientFormData.helpsWithHints(focusedAutofillHints)) {
-                        hasDataForFocusedAutofillHints = true;
-                    }
-                    if (clientFormData.helpsWithHints(allAutofillHints)) {
-                        clientFormDataMap.put(clientFormData.getDatasetName(), clientFormData);
-                    }
-                }
-            }
-            if (hasDataForFocusedAutofillHints) {
-                return clientFormDataMap;
-            } else {
-                return null;
-            }
-        } catch (JSONException e) {
-            return null;
-        }
-    }
-
-    @Override
-    public void saveClientFormData(ClientFormData clientFormData) {
-        //TODO use sqlite instead.
-        String datasetName = "dataset-" + getDatasetNumber();
-        clientFormData.setDatasetName(datasetName);
-        Set<String> allAutofillData = getAllAutofillDataStringSet();
-        allAutofillData.add(clientFormData.toJson().toString());
-        saveAllAutofillDataStringSet(allAutofillData);
-        incrementDatasetNumber();
-    }
-
-    @Override
-    public void clear() {
-        mPrefs.edit().remove(CLIENT_FORM_DATA_KEY).apply();
-    }
-
-    private Set<String> getAllAutofillDataStringSet() {
-        return mPrefs.getStringSet(CLIENT_FORM_DATA_KEY, new ArraySet<String>());
-    }
-
-    private void saveAllAutofillDataStringSet(Set<String> allAutofillDataStringSet) {
-        mPrefs.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() {
-        return mPrefs.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() {
-        mPrefs.edit().putInt(DATASET_NUMBER_KEY, getDatasetNumber() + 1).apply();
-    }
-}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java
deleted file mode 100644
index 4d4de2b..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java
+++ /dev/null
@@ -1,120 +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.service.model;
-
-import android.app.assist.AssistStructure;
-import android.service.autofill.SaveInfo;
-import android.view.View;
-import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillValue;
-
-/**
- * Class that represents a field that can be autofilled. It will contain a description
- * (what type data the field holds), an AutoFillId (an ID unique to the rest of the ViewStructure),
- * and a value (what data is currently in the field).
- */
-public class AutofillField {
-    private int mSaveType = 0;
-    private String[] mHints;
-    private AutofillId mId;
-    private int mAutofillType;
-    private String[] mAutofillOptions;
-    private boolean mFocused;
-
-    public AutofillField(AssistStructure.ViewNode view) {
-        mId = view.getAutofillId();
-        setHints(view.getAutofillHints());
-        mAutofillType = view.getAutofillType();
-        mAutofillOptions = view.getAutofillOptions();
-        mFocused = view.isFocused();
-    }
-
-    public String[] getHints() {
-        return mHints;
-    }
-
-    public void setHints(String[] hints) {
-        mHints = hints;
-        updateSaveTypeFromHints();
-    }
-
-    public int getSaveType() {
-        return mSaveType;
-    }
-
-    public AutofillId getId() {
-        return mId;
-    }
-
-    public void setId(AutofillId id) {
-        mId = id;
-    }
-
-    public int getAutofillType() {
-        return mAutofillType;
-    }
-
-    public int getAutofillOptionIndex(String value) {
-        for (int i = 0; i < mAutofillOptions.length; i++) {
-            if (mAutofillOptions[i].equals(value)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    public boolean isFocused() {
-        return mFocused;
-    }
-
-    private void updateSaveTypeFromHints() {
-        mSaveType = 0;
-        if (mHints == null) {
-            return;
-        }
-        for (String hint : mHints) {
-            switch (hint) {
-                case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE:
-                case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY:
-                case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH:
-                case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR:
-                case View.AUTOFILL_HINT_CREDIT_CARD_NUMBER:
-                case View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
-                    break;
-                case View.AUTOFILL_HINT_EMAIL_ADDRESS:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
-                    break;
-                case View.AUTOFILL_HINT_PHONE:
-                case View.AUTOFILL_HINT_NAME:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_GENERIC;
-                    break;
-                case View.AUTOFILL_HINT_PASSWORD:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_PASSWORD;
-                    mSaveType &= ~SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
-                    mSaveType &= ~SaveInfo.SAVE_DATA_TYPE_USERNAME;
-                    break;
-                case View.AUTOFILL_HINT_POSTAL_ADDRESS:
-                case View.AUTOFILL_HINT_POSTAL_CODE:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_ADDRESS;
-                    break;
-                case View.AUTOFILL_HINT_USERNAME:
-                    mSaveType |= SaveInfo.SAVE_DATA_TYPE_USERNAME;
-                    break;
-            }
-        }
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java
deleted file mode 100644
index 0354b98..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java
+++ /dev/null
@@ -1,70 +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.service.model;
-
-import android.view.autofill.AutofillId;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-public final class AutofillFieldsCollection {
-
-    private final List<AutofillId> mAutofillIds = new ArrayList<>();
-    private final HashMap<String, List<AutofillField>> mAutofillHintsToFieldsMap = new HashMap<>();
-    private final List<String> mAllAutofillHints = new ArrayList<>();
-    private final List<String> mFocusedAutofillHints = new ArrayList<>();
-    private int size = 0;
-    private int mSaveType = 0;
-
-    public void add(AutofillField autofillField) {
-        mSaveType |= autofillField.getSaveType();
-        size++;
-        mAutofillIds.add(autofillField.getId());
-        List<String> hintsList = Arrays.asList(autofillField.getHints());
-        mAllAutofillHints.addAll(hintsList);
-        if (autofillField.isFocused()) {
-            mFocusedAutofillHints.addAll(hintsList);
-        }
-        for (String hint : autofillField.getHints()) {
-            if (mAutofillHintsToFieldsMap.get(hint) == null) {
-                mAutofillHintsToFieldsMap.put(hint, new ArrayList<AutofillField>());
-            }
-            mAutofillHintsToFieldsMap.get(hint).add(autofillField);
-        }
-    }
-
-    public int getSaveType() {
-        return mSaveType;
-    }
-
-    public AutofillId[] getAutofillIds() {
-        return mAutofillIds.toArray(new AutofillId[size]);
-    }
-
-    public List<AutofillField> getFieldsForHint(String hint) {
-        return mAutofillHintsToFieldsMap.get(hint);
-    }
-
-    public List<String> getFocusedHints() {
-        return mFocusedAutofillHints;
-    }
-
-    public List<String> getAllHints() {
-        return mAllAutofillHints;
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java
deleted file mode 100644
index aa57e93..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java
+++ /dev/null
@@ -1,184 +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.service.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 org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-/**
- * ClientFormData 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 ClientFormData {
-    private static final String TAG = "ClientFormData";
-    private final HashMap<String, SavedAutofillValue> hintMap;
-    private String datasetName;
-
-    public ClientFormData() {
-        this(null, new HashMap<String, SavedAutofillValue>());
-    }
-
-    public ClientFormData(String datasetName, HashMap<String, SavedAutofillValue> hintMap) {
-        this.hintMap = hintMap;
-        this.datasetName = datasetName;
-    }
-
-    public static ClientFormData fromJson(JSONObject jsonObject) {
-        HashMap<String, SavedAutofillValue> hintMap = new HashMap<>();
-        try {
-            String datasetName = jsonObject.has("datasetName") ?
-                    jsonObject.getString("datasetName") : null;
-            JSONObject valuesJson = jsonObject.getJSONObject("values");
-            Iterator<String> hints = valuesJson.keys();
-            while (hints.hasNext()) {
-                String hint = hints.next();
-                JSONObject valueAsJson = valuesJson
-                        .getJSONObject(hint);
-                if (valueAsJson != null) {
-                    SavedAutofillValue savedAutofillValue = SavedAutofillValue.fromJson(valueAsJson);
-                    hintMap.put(hint, savedAutofillValue);
-                }
-            }
-            return new ClientFormData(datasetName, hintMap);
-        } catch (JSONException e) {
-            Log.d(TAG, e.getMessage());
-            return null;
-        }
-    }
-
-    /**
-     * Returns the name of the {@link Dataset}.
-     */
-    public String getDatasetName() {
-        return this.datasetName;
-    }
-
-    /**
-     * Sets the {@link Dataset} name.
-     */
-    public void setDatasetName(String datasetName) {
-        this.datasetName = datasetName;
-    }
-
-    /**
-     * Sets values for a list of hints.
-     */
-    public void set(@NonNull String[] autofillHints, @NonNull SavedAutofillValue autofillValue) {
-        if (autofillHints.length < 1) {
-            return;
-        }
-        for (int i = 0; i < autofillHints.length; i++) {
-            hintMap.put(autofillHints[i], autofillValue);
-        }
-    }
-
-    /**
-     * Populates a {@link Dataset.Builder} with appropriate values for each {@link AutofillId}
-     * in a {@code AutofillFieldsCollection}.
-     */
-    public boolean applyToFields(AutofillFieldsCollection autofillFieldsCollection,
-            Dataset.Builder datasetBuilder) {
-        boolean setValueAtLeastOnce = false;
-        List<String> allHints = autofillFieldsCollection.getAllHints();
-        for (int hintIndex = 0; hintIndex < allHints.size(); hintIndex++) {
-            String hint = allHints.get(hintIndex);
-            List<AutofillField> autofillFields = autofillFieldsCollection.getFieldsForHint(hint);
-            if (autofillFields == null) {
-                continue;
-            }
-            for (int autofillFieldIndex = 0; autofillFieldIndex < autofillFields.size(); autofillFieldIndex++) {
-                AutofillField autofillField = autofillFields.get(autofillFieldIndex);
-                AutofillId autofillId = autofillField.getId();
-                int autofillType = autofillField.getAutofillType();
-                SavedAutofillValue savedAutofillValue = hintMap.get(hint);
-                switch (autofillType) {
-                    case View.AUTOFILL_TYPE_LIST:
-                        int listValue = autofillField.getAutofillOptionIndex(savedAutofillValue.getTextValue());
-                        if (listValue != -1) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forList(listValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_DATE:
-                        long dateValue = savedAutofillValue.getDateValue();
-                        if (dateValue != -1) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forDate(dateValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_TEXT:
-                        String textValue = savedAutofillValue.getTextValue();
-                        if (textValue != null) {
-                            datasetBuilder.setValue(autofillId, AutofillValue.forText(textValue));
-                            setValueAtLeastOnce = true;
-                        }
-                        break;
-                    case View.AUTOFILL_TYPE_TOGGLE:
-                        if (savedAutofillValue.hasToggleValue()) {
-                            boolean toggleValue = savedAutofillValue.getToggleValue();
-                            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;
-    }
-
-    public JSONObject toJson() {
-        JSONObject jsonObject = new JSONObject();
-        try {
-            jsonObject.put("datasetName", datasetName != null ? datasetName : JSONObject.NULL);
-            JSONObject jsonValues = new JSONObject();
-            Set<String> hints = hintMap.keySet();
-            for (String hint : hints) {
-                SavedAutofillValue value = hintMap.get(hint);
-                jsonValues.put(hint, value != null ? value.toJson() : JSONObject.NULL);
-            }
-            jsonObject.put("values", jsonValues);
-        } catch (JSONException e) {
-            Log.e(TAG, e.getMessage());
-        }
-        return jsonObject;
-    }
-
-    public boolean helpsWithHints(List<String> autofillHints) {
-        for (int i = 0; i < autofillHints.size(); i++) {
-            String autofillHint = autofillHints.get(i);
-            if (hintMap.get(autofillHint) != null && !hintMap.get(autofillHint).isNull()) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.java
deleted file mode 100644
index 73e0c81..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.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.service.model;
-
-import android.app.assist.AssistStructure;
-import android.util.Log;
-import android.view.autofill.AutofillValue;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-public class SavedAutofillValue {
-    private static final String TAG = "SavedAutofillValue";
-    private String textValue = null;
-    private Long dateValue = -1L;
-    private Boolean toggleValue = false;
-    private boolean hasToggleValue = false;
-
-    public static SavedAutofillValue fromJson(JSONObject jsonObject) {
-        if (jsonObject == null) {
-            return null;
-        }
-        try {
-            SavedAutofillValue savedAutofillValue = new SavedAutofillValue();
-
-            savedAutofillValue.textValue =
-                    !jsonObject.isNull("textValue") ? jsonObject.getString("textValue") : null;
-            savedAutofillValue.dateValue =
-                    !jsonObject.isNull("dateValue") ? jsonObject.getLong("dateValue") : null;
-            savedAutofillValue.setToggleValue
-                    (!jsonObject.isNull("toggleValue") ? jsonObject.getBoolean("toggleValue") : null);
-            return savedAutofillValue;
-        } catch (JSONException e) {
-            Log.e(TAG, e.getMessage());
-            return null;
-        }
-    }
-
-    public static SavedAutofillValue fromViewNode(AssistStructure.ViewNode viewNode) {
-        SavedAutofillValue savedAutofillValue = new SavedAutofillValue();
-        AutofillValue autofillValue = viewNode.getAutofillValue();
-        if (autofillValue != null) {
-            if (autofillValue.isList()) {
-                String[] autofillOptions = viewNode.getAutofillOptions();
-                int index = autofillValue.getListValue();
-                if (autofillOptions != null && autofillOptions.length > 0) {
-                    savedAutofillValue.textValue = autofillOptions[index];
-                }
-            } else if (autofillValue.isDate()) {
-                savedAutofillValue.dateValue = autofillValue.getDateValue();
-            } else if (autofillValue.isText()) {
-                // Using toString of AutofillValue.getTextValue in order to save it to
-                // SharedPreferences.
-                savedAutofillValue.textValue = autofillValue.getTextValue().toString();
-            }
-        }
-        return savedAutofillValue;
-    }
-
-    public JSONObject toJson() {
-        JSONObject jsonObject = new JSONObject();
-        try {
-            jsonObject.put("textValue", textValue != null ? textValue : JSONObject.NULL);
-            jsonObject.put("dateValue", dateValue != null ? dateValue : JSONObject.NULL);
-            jsonObject.put("toggleValue", toggleValue != null ? toggleValue : JSONObject.NULL);
-            return jsonObject;
-        } catch (JSONException e) {
-            Log.e(TAG, e.getMessage());
-            return null;
-        }
-    }
-
-    public String getTextValue() {
-        return textValue;
-    }
-
-    public long getDateValue() {
-        return dateValue;
-    }
-
-
-    public boolean getToggleValue() {
-        return toggleValue;
-    }
-
-    public void setToggleValue(Boolean toggleValue) {
-        this.toggleValue = toggleValue;
-        hasToggleValue = toggleValue != null;
-    }
-
-
-    public boolean isNull() {
-        return textValue == null && dateValue == -1L && !hasToggleValue;
-    }
-
-    public boolean hasToggleValue() {
-        return hasToggleValue;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        SavedAutofillValue that = (SavedAutofillValue) o;
-
-        if (textValue != null ? !textValue.equals(that.textValue) : that.textValue != null)
-            return false;
-        if (dateValue != null ? !dateValue.equals(that.dateValue) : that.dateValue != null)
-            return false;
-        return toggleValue != null ? toggleValue.equals(that.toggleValue) : that.toggleValue == null;
-
-    }
-
-    @Override
-    public int hashCode() {
-        int result = textValue != null ? textValue.hashCode() : 0;
-        result = 31 * result + (dateValue != null ? dateValue.hashCode() : 0);
-        result = 31 * result + (toggleValue != null ? toggleValue.hashCode() : 0);
-        return result;
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.java
deleted file mode 100644
index 3926530..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.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.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;
-
-public class MyPreferences {
-    private static final String TAG = "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/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java
deleted file mode 100644
index 6387d36..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java
+++ /dev/null
@@ -1,176 +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.service.settings;
-
-import android.content.DialogInterface;
-import android.os.Bundle;
-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.widget.CompoundButton;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.datasource.LocalAutofillRepository;
-
-public class SettingsActivity extends AppCompatActivity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.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(),
-                new CompoundButton.OnCheckedChangeListener() {
-                    @Override
-                    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
-                        preferences.setResponseAuth(b);
-                    }
-                });
-        setupSettingsSwitch(R.id.settings_auth_datasets_container,
-                R.id.settings_auth_datasets_label,
-                R.id.settings_auth_datasets_switch,
-                preferences.isDatasetAuth(),
-                new CompoundButton.OnCheckedChangeListener() {
-                    @Override
-                    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
-                        preferences.setDatasetAuth(b);
-                    }
-                });
-        setupSettingsButton(R.id.settings_clear_data_container,
-                R.id.settings_clear_data_label,
-                R.id.settings_clear_data_icon,
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        buildClearDataDialog().show();
-                    }
-                });
-
-        setupSettingsButton(R.id.settings_auth_credentials_container,
-                R.id.settings_auth_credentials_label,
-                R.id.settings_auth_credentials_icon,
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View 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, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        LocalAutofillRepository.getInstance
-                                (SettingsActivity.this).clear();
-                        MyPreferences.getInstance(SettingsActivity.this)
-                                .clearCredentials();
-                        dialog.dismiss();
-                    }
-                })
-                .create();
-    }
-
-    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.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.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, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int 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 = (ViewGroup) findViewById(containerId);
-        String switchLabel = ((TextView) container.findViewById(labelId)).getText().toString();
-        final Switch switchView = container.findViewById(switchId);
-        switchView.setContentDescription(switchLabel);
-        switchView.setChecked(checked);
-        container.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                switchView.performClick();
-            }
-        });
-        switchView.setOnCheckedChangeListener(checkedChangeListener);
-    }
-
-    private void setupSettingsButton(int containerId, int labelId, int imageViewId,
-            final View.OnClickListener onClickListener) {
-        ViewGroup container = (ViewGroup) findViewById(containerId);
-        String buttonLabel = ((TextView) container.findViewById(labelId)).getText().toString();
-        final ImageView imageView = container.findViewById(imageViewId);
-        imageView.setContentDescription(buttonLabel);
-        container.setOnClickListener(onClickListener);
-    }
-}
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_autocomplete_logo_24dp.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_autocomplete_logo_24dp.xml
new file mode 100644
index 0000000..80f30a2
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_autocomplete_logo_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_custom_virtual_logo_24dp.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_custom_virtual_logo_24dp.xml
new file mode 100644
index 0000000..3a8ee3b
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_custom_virtual_logo_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_edittexts_logo_24dp.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_edittexts_logo_24dp.xml
new file mode 100644
index 0000000..17e403d
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_edittexts_logo_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:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M4,9h16v2L4,11zM4,13h10v2L4,15z"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_email_black_24dp.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_email_black_24dp.xml
new file mode 100644
index 0000000..174c127
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_email_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_info_black_24dp.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_info_black_24dp.xml
new file mode 100644
index 0000000..c297121
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_info_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_lock_black_24dp.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_lock_black_24dp.xml
new file mode 100644
index 0000000..6b2f014
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/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: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/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_send_white_24dp.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_send_white_24dp.xml
new file mode 100644
index 0000000..f614267
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_send_white_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:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_spinners_logo_24dp.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_spinners_logo_24dp.xml
new file mode 100644
index 0000000..5fb27a2
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_spinners_logo_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:viewportWidth="24.0"
+        android:viewportHeight="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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_view_module_black_24dp.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_view_module_black_24dp.xml
new file mode 100644
index 0000000..ab36b07
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/drawable/ic_view_module_black_24dp.xml
@@ -0,0 +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">
+    <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"/>
+</vector>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/activity_main.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/activity_main.xml
index 26d0657..f441a2c 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/activity_main.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/activity_main.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,33 +13,72 @@
  * 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/activity_vertical_margin"
-              android:paddingRight="@dimen/activity_horizontal_margin"
-              android:paddingStart="@dimen/activity_horizontal_margin"
-              android:paddingTop="@dimen/activity_vertical_margin">
+<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">
 
-    <Button
-        android:id="@+id/standardViewSignInButton"
+    <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:text="@string/standard_view_sign_in" />
+        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">
 
-    <Button
-        android:id="@+id/virtualViewSignInButton"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/activity_vertical_margin"
-        android:text="@string/virtual_view_sign_in" />
+        <com.example.android.autofillframework.app.NavigationItem
+            android:id="@+id/standardViewSignInButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:infoText="@string/edittext_login_info"
+            app:labelText="@string/navigation_button_edittext_login_label"
+            app:itemLogo="@drawable/ic_edittexts_logo_24dp"
+            app:imageColor="@android:color/holo_red_dark" />
 
-    <Button
-        android:id="@+id/creditCardCheckoutButton"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/activity_vertical_margin"
-        android:text="@string/credit_card_checkout" />
+        <com.example.android.autofillframework.app.NavigationItem
+            android:id="@+id/standardLoginWithAutoCompleteButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:infoText="@string/autocomplete_login_info"
+            app:labelText="@string/navigation_button_autocomplete_login_label"
+            app:itemLogo="@drawable/ic_autocomplete_logo_24dp"
+            app:imageColor="@android:color/holo_blue_dark"/>
 
-</LinearLayout>
\ No newline at end of file
+        <com.example.android.autofillframework.app.NavigationItem
+            android:id="@+id/virtualViewSignInButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:infoText="@string/custom_virtual_login_info"
+            app:labelText="@string/navigation_button_custom_virtual_view_login_label"
+            app:itemLogo="@drawable/ic_custom_virtual_logo_24dp"
+            app:imageColor="@android:color/holo_green_dark"/>
+
+        <com.example.android.autofillframework.app.NavigationItem
+            android:id="@+id/creditCardCheckoutButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:infoText="@string/spinners_credit_card_info"
+            app:labelText="@string/navigation_button_spinners_credit_card_label"
+            app:itemLogo="@drawable/ic_spinners_logo_24dp"
+            app:imageColor="@android:color/holo_orange_dark"/>
+
+        <com.example.android.autofillframework.app.NavigationItem
+            android:id="@+id/emailComposeButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:infoText="@string/email_compose_info"
+            app:labelText="@string/navigation_button_email_compose_label"
+            app:itemLogo="@drawable/ic_email_black_24dp"
+            app:imageColor="@android:color/holo_purple"/>
+        <com.example.android.autofillframework.app.NavigationItem
+            android:id="@+id/creditCardCompoundViewButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:infoText="@string/compound_view_credit_card_info"
+            app:labelText="@string/navigation_button_compound_view_credit_card_label"
+            app:imageColor="@android:color/holo_blue_light"
+            app:itemLogo="@drawable/ic_view_module_black_24dp" />
+
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/auth_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/auth_activity.xml
deleted file mode 100644
index 4b5926a..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/auth_activity.xml
+++ /dev/null
@@ -1,62 +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"
-              xmlns:tools="http://schemas.android.com/tools"
-              android:id="@+id/authLayout"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              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=".service.AuthActivity">
-
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:text="Master password">
-    </TextView>
-
-    <EditText
-        android:id="@+id/master_password"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:inputType="textPassword">
-    </EditText>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center"
-        android:orientation="horizontal">
-
-        <Button
-            android:id="@+id/cancel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Cancel" />
-
-        <Button
-            android:id="@+id/login"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Login" />
-    </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/cc_exp_date.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/cc_exp_date.xml
new file mode 100644
index 0000000..aebe9f8
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/cc_exp_date.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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <android.support.constraint.ConstraintLayout
+        android:id="@+id/navigation_item_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <Spinner
+            android:id="@+id/ccExpMonth"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="8dp"
+            android:contentDescription="@string/cc_exp_month_description"
+            app:layout_constraintBottom_toBottomOf="@+id/monthYearDelimiter"
+            app:layout_constraintEnd_toStartOf="@+id/monthYearDelimiter"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/monthYearDelimiter" />
+
+        <TextView
+            android:id="@+id/monthYearDelimiter"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/slash"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/ccExpYear"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toEndOf="@+id/ccExpMonth"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <Spinner
+            android:id="@+id/ccExpYear"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:contentDescription="@string/cc_exp_year_description"
+            app:layout_constraintBottom_toBottomOf="@+id/monthYearDelimiter"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toEndOf="@+id/monthYearDelimiter"
+            app:layout_constraintTop_toTopOf="@+id/monthYearDelimiter" />
+    </android.support.constraint.ConstraintLayout>
+</merge>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/credit_card_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/credit_card_activity.xml
index 7d8e099..7f78c4e 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/credit_card_activity.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/credit_card_activity.xml
@@ -14,95 +14,136 @@
  * 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/standardLoginLayout"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:focusable="true"
-              android:focusableInTouchMode="true"
-              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">
+<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"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin">
 
-    <RelativeLayout
+    <TextView
+        android:id="@+id/spinners_credit_card_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_spinners_credit_card_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center">
+        android:background="@drawable/ic_info_black_24dp"
+        app:layout_constraintBottom_toBottomOf="@+id/spinners_credit_card_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/spinners_credit_card_header"
+        app:layout_constraintTop_toTopOf="@+id/spinners_credit_card_header"
+        app:dialogText="@string/spinners_credit_card_info" />
 
-        <TextView
-            android:id="@+id/creditCardNumberLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="20dp"
-            android:importantForAutofill="no"
-            android:text="@string/credit_card_number_label" />
-
-        <EditText
-            android:id="@+id/creditCardNumberField"
-            android:layout_width="200sp"
-            android:layout_height="wrap_content"
-            android:layout_alignBaseline="@+id/creditCardNumberLabel"
-            android:layout_toEndOf="@id/creditCardNumberLabel"
-            android:autofillHints="creditCardNumber" />
-
-        <TextView
-            android:id="@+id/creditCardExpirationLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignStart="@+id/creditCardNumberLabel"
-            android:layout_below="@+id/creditCardNumberLabel"
-            android:layout_marginTop="20dp"
-            android:importantForAutofill="no"
-            android:text="@string/credit_card_expiration_label" />
-
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignBaseline="@+id/creditCardExpirationLabel"
-            android:layout_alignStart="@+id/creditCardNumberField"
-            android:orientation="horizontal">
-
-            <Spinner
-                android:id="@+id/expirationDay"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:autofillHints="creditCardExpirationDay" />
-
-            <Spinner
-                android:id="@+id/expirationMonth"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:autofillHints="creditCardExpirationMonth" />
-
-            <Spinner
-                android:id="@+id/expirationYear"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:autofillHints="creditCardExpirationYear" />
-        </LinearLayout>
-
-    </RelativeLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
+    <TextView
+        android:id="@+id/creditCardNumberLabel"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
-        android:gravity="center"
-        android:orientation="horizontal">
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:labelFor="@+id/creditCardNumberField"
+        android:text="@string/credit_card_number_label"
+        app:layout_constraintStart_toStartOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintTop_toBottomOf="@+id/spinners_credit_card_header" />
 
-        <Button
-            android:id="@+id/clear"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Clear" />
+    <EditText
+        android:id="@+id/creditCardNumberField"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/creditCardNumberLabel"
+        android:layout_marginEnd="8dp"
+        android:autofillHints="creditCardNumber"
+        android:focusedByDefault="true"
+        android:inputType="number"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardNumberLabel"
+        app:layout_constraintEnd_toEndOf="@+id/expirationYear"
+        app:layout_constraintStart_toStartOf="@+id/expirationDay"
+        app:layout_constraintTop_toTopOf="@+id/creditCardNumberLabel" />
 
-        <Button
-            android:id="@+id/submit"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Submit" />
-    </LinearLayout>
+    <TextView
+        android:id="@+id/creditCardExpirationLabel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:importantForAutofill="no"
+        android:text="@string/credit_card_expiration_label"
+        app:layout_constraintEnd_toStartOf="@+id/expirationDay"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardNumberLabel" />
 
-</LinearLayout>
\ No newline at end of file
+    <Spinner
+        android:id="@+id/expirationDay"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:autofillHints="creditCardExpirationDay"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintEnd_toStartOf="@+id/expirationMonth"
+        app:layout_constraintStart_toEndOf="@+id/creditCardNumberLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardExpirationLabel" />
+
+    <Spinner
+        android:id="@+id/expirationMonth"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:autofillHints="creditCardExpirationMonth"
+        app:layout_constraintBottom_toBottomOf="@+id/expirationDay"
+        app:layout_constraintEnd_toStartOf="@+id/expirationYear"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/expirationDay"
+        app:layout_constraintTop_toTopOf="@+id/expirationDay" />
+
+    <Spinner
+        android:id="@+id/expirationYear"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:autofillHints="creditCardExpirationYear"
+        app:layout_constraintBottom_toBottomOf="@+id/expirationMonth"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/expirationMonth"
+        app:layout_constraintTop_toTopOf="@+id/expirationMonth" />
+
+    <TextView
+        android:id="@+id/clear"
+        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_large"
+        android:text="@string/clear_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toStartOf="@+id/submit"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardExpirationLabel" />
+
+    <TextView
+        android:id="@+id/submit"
+        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/submit_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/clear"
+        app:layout_constraintTop_toTopOf="@+id/clear" />
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/credit_card_compound_view_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/credit_card_compound_view_activity.xml
new file mode 100644
index 0000000..e95d052
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/credit_card_compound_view_activity.xml
@@ -0,0 +1,135 @@
+<?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"
+    android:id="@+id/authLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    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">
+
+    <TextView
+        android:id="@+id/standard_login_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_compound_view_credit_card_label"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/compound_view_credit_card_info"
+        app:layout_constraintBottom_toBottomOf="@+id/standard_login_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/standard_login_header"
+        app:layout_constraintTop_toTopOf="@+id/standard_login_header" />
+
+    <TextView
+        android:id="@+id/creditCardNumberLabel"
+        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/creditCardNumberField"
+        android:text="@string/credit_card_number_label"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/standard_login_header" />
+
+    <EditText
+        android:id="@+id/creditCardNumberField"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:autofillHints="creditCardNumber"
+        android:ems="12"
+        android:inputType="number"
+        android:paddingHorizontal="@dimen/spacing_micro"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardNumberLabel"
+        app:layout_constraintStart_toEndOf="@+id/creditCardNumberLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardNumberLabel" />
+
+    <TextView
+        android:id="@+id/creditCardExpirationLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/creditCardExpirationView"
+        android:text="@string/credit_card_expiration_label"
+        app:layout_constraintStart_toStartOf="@id/creditCardNumberLabel"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardNumberLabel" />
+
+    <com.example.android.autofillframework.app.CreditCardExpirationDateView
+        android:id="@+id/creditCardExpirationView"
+        android:layout_width="250dp"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:autofillHints="creditCardExpirationDate"
+        app:layout_constraintBottom_toBottomOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/creditCardExpirationLabel"
+        app:layout_constraintTop_toTopOf="@+id/creditCardExpirationLabel" />
+
+    <TextView
+        android:id="@+id/clearButton"
+        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/clear_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toStartOf="@+id/submitButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/creditCardExpirationView" />
+
+    <TextView
+        android:id="@+id/submitButton"
+        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/submit_label"
+        android:textColor="@android:color/holo_blue_dark"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/clearButton"
+        app:layout_constraintTop_toTopOf="@+id/clearButton" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/email_compose_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/email_compose_activity.xml
new file mode 100644
index 0000000..0b7519f
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/email_compose_activity.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.
+-->
+<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"
+    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">
+
+
+    <TextView
+        android:id="@+id/email_compose_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:gravity="center"
+        android:text="@string/navigation_button_email_compose_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/ic_info_black_24dp"
+        app:dialogText="@string/email_compose_info"
+        app:layout_constraintBottom_toBottomOf="@+id/email_compose_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/email_compose_header"
+        app:layout_constraintTop_toTopOf="@+id/email_compose_header" />
+
+    <TextView
+        android:id="@+id/toLabel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/spacing_normal"
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:text="@string/to_label"
+        app:layout_constraintBottom_toBottomOf="@+id/toText"
+        app:layout_constraintEnd_toStartOf="@+id/toText"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/toText" />
+
+    <EditText
+        android:id="@+id/toText"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:inputType="textEmailAddress"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="@+id/bodyText"
+        app:layout_constraintTop_toBottomOf="@+id/email_compose_header" />
+
+    <TextView
+        android:id="@+id/bodyLabel"
+        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/body_label"
+        app:layout_constraintEnd_toStartOf="@+id/bodyText"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/placeholder"
+        app:layout_constraintBottom_toBottomOf="@+id/placeholder"/>
+
+    <EditText
+        android:id="@+id/bodyText"
+        android:layout_width="0dp"
+        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="textMultiLine"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/bodyLabel"
+        app:layout_constraintTop_toBottomOf="@+id/toText" />
+
+    <View
+        android:id="@+id/placeholder"
+        android:layout_width="match_parent"
+        android:layout_height="36sp"
+        app:layout_constraintTop_toTopOf="@+id/bodyText"
+        app:layout_constraintStart_toStartOf="parent"
+        android:layout_marginStart="8dp" />
+
+    <android.support.design.widget.FloatingActionButton
+        android:id="@+id/sendButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="8dp"
+        android:layout_marginEnd="8dp"
+        android:backgroundTint="@android:color/holo_purple"
+        android:src="@drawable/ic_send_white_24dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/list_item.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/list_item.xml
deleted file mode 100644
index d01bc37..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/list_item.xml
+++ /dev/null
@@ -1,26 +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.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-          android:id="@+id/text1"
-          android:layout_width="fill_parent"
-          android:layout_height="fill_parent"
-          android:background="#ffffffff"
-          android:gravity="center_vertical"
-          android:minHeight="?android:attr/listPreferredItemHeightSmall"
-          android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-          android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-          android:textAppearance="?android:attr/textAppearanceListItemSmall" />
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/login_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/login_activity.xml
index 6382fe7..1bbac85 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/login_activity.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/login_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,78 +13,131 @@
  * 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/standardLoginLayout"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:focusable="true"
-              android:focusableInTouchMode="true"
-              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">
+<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: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" >
 
-    <RelativeLayout
+    <TextView
+        android:id="@+id/standard_login_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:text="@string/navigation_button_edittext_login_label"
+        android:gravity="center"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center">
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:background="@drawable/ic_info_black_24dp"
+        app:layout_constraintBottom_toBottomOf="@+id/standard_login_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/standard_login_header"
+        app:layout_constraintTop_toTopOf="@+id/standard_login_header"
+        app:dialogText="@string/edittext_login_info"/>
 
-        <TextView
-            android:id="@+id/usernameLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="20dp"
-            android:importantForAutofill="no"
-            android:text="@string/username_label" />
-
-        <EditText
-            android:id="@+id/usernameField"
-            android:layout_width="200sp"
-            android:layout_height="wrap_content"
-            android:layout_alignBaseline="@+id/usernameLabel"
-            android:layout_toEndOf="@id/usernameLabel"
-            android:autofillHints="username"
-            android:inputType="textPersonName" />
-
-        <TextView
-            android:id="@+id/passwordLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignStart="@+id/usernameLabel"
-            android:layout_below="@+id/usernameLabel"
-            android:layout_marginTop="20dp"
-            android:importantForAutofill="no"
-            android:text="@string/password_label" />
-
-        <EditText
-            android:id="@+id/passwordField"
-            android:layout_width="200sp"
-            android:layout_height="wrap_content"
-            android:layout_alignBaseline="@+id/passwordLabel"
-            android:layout_alignStart="@+id/usernameField"
-            android:autofillHints="password"
-            android:inputType="textPassword" />
-    </RelativeLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
+    <TextView
+        android:id="@+id/usernameLabel"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
-        android:gravity="center"
-        android:orientation="horizontal">
+        android:layout_marginEnd="@dimen/spacing_normal"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:labelFor="@+id/usernameField"
+        android:text="@string/username_label"
+        app:layout_constraintEnd_toStartOf="@+id/usernameField"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/standard_login_header" />
 
-        <Button
-            android:id="@+id/clear"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Clear" />
+    <EditText
+        android:id="@+id/usernameField"
+        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:autofillHints="username"
+        android:inputType="text"
+        app:layout_constraintBottom_toBottomOf="@+id/usernameLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/usernameLabel"
+        app:layout_constraintTop_toTopOf="@+id/usernameLabel" />
 
-        <Button
-            android:id="@+id/login"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Login" />
-    </LinearLayout>
+    <TextView
+        android:id="@+id/passwordLabel"
+        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/passwordField"
+        android:text="@string/password_label"
+        app:layout_constraintEnd_toStartOf="@+id/passwordField"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/usernameLabel" />
 
-</LinearLayout>
\ No newline at end of file
+    <EditText
+        android:id="@+id/passwordField"
+        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:autofillHints="password"
+        android:inputType="textPassword"
+        app:layout_constraintBottom_toBottomOf="@+id/passwordLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/passwordLabel"
+        app:layout_constraintTop_toTopOf="@+id/passwordLabel" />
+
+    <TextView
+        android:id="@+id/clear"
+        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/clear_label"
+        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/passwordField" />
+
+    <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/clear"
+        app:layout_constraintTop_toTopOf="@+id/clear" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/login_with_autocomplete_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/login_with_autocomplete_activity.xml
new file mode 100644
index 0000000..a7efa42
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/login_with_autocomplete_activity.xml
@@ -0,0 +1,140 @@
+<?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"
+    android:id="@+id/authLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    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" >
+
+    <TextView
+        android:id="@+id/standard_login_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_autocomplete_login_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/ic_info_black_24dp"
+        app:layout_constraintBottom_toBottomOf="@+id/standard_login_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/standard_login_header"
+        app:layout_constraintTop_toTopOf="@+id/standard_login_header"
+        app:dialogText="@string/autocomplete_login_info"/>
+
+    <TextView
+        android:id="@+id/usernameLabel"
+        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/usernameField"
+        android:text="@string/username_label"
+        app:layout_constraintEnd_toStartOf="@+id/usernameField"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/standard_login_header" />
+
+    <AutoCompleteTextView
+        android:id="@+id/usernameField"
+        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:autofillHints="username"
+        android:inputType="text"
+        app:layout_constraintBottom_toBottomOf="@+id/usernameLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/usernameLabel"
+        app:layout_constraintTop_toTopOf="@+id/usernameLabel" />
+
+    <TextView
+        android:id="@+id/passwordLabel"
+        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/passwordField"
+        android:text="@string/password_label"
+        app:layout_constraintEnd_toStartOf="@+id/passwordField"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/usernameLabel" />
+
+    <AutoCompleteTextView
+        android:id="@+id/passwordField"
+        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:autofillHints="password"
+        android:inputType="textPassword"
+        app:layout_constraintBottom_toBottomOf="@+id/passwordLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/passwordLabel"
+        app:layout_constraintTop_toTopOf="@+id/passwordLabel" />
+
+    <TextView
+        android:id="@+id/clear"
+        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/passwordField" />
+
+    <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/clear"
+        app:layout_constraintTop_toTopOf="@+id/clear" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/multidataset_service_auth_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/multidataset_service_auth_activity.xml
new file mode 100644
index 0000000..981dd0d
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/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=".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/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/multidataset_service_list_item.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/multidataset_service_list_item.xml
new file mode 100644
index 0000000..442d54e
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/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/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/settings_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/multidataset_service_settings_activity.xml
similarity index 100%
rename from prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/settings_activity.xml
rename to prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/multidataset_service_settings_activity.xml
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/settings_authentication_dialog.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml
similarity index 100%
rename from prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/settings_authentication_dialog.xml
rename to prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/multidataset_service_settings_authentication_dialog.xml
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/navigation_button.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/navigation_button.xml
new file mode 100644
index 0000000..a0dba90
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/navigation_button.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+    <LinearLayout
+        android:id="@+id/navigation_button_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <ImageButton
+            android:id="@+id/infoButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
+            android:layout_marginVertical="@dimen/activity_vertical_margin"
+            android:background="@drawable/ic_info_black_24dp" />
+
+        <TextView
+            style="@style/TextAppearance.AppCompat.Medium"
+            android:id="@+id/buttonLabel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:minLines="2"
+            android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
+            android:layout_marginVertical="@dimen/activity_vertical_margin"
+            tools:text="@string/navigation_button_edittext_login_label" />
+    </LinearLayout>
+</merge>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/navigation_item.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/navigation_item.xml
new file mode 100644
index 0000000..581dbb2
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/navigation_item.xml
@@ -0,0 +1,67 @@
+<?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.
+-->
+<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">
+
+    <android.support.constraint.ConstraintLayout
+        android:id="@+id/navigation_item_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginVertical="@dimen/spacing_micro">
+
+        <android.support.v7.widget.CardView
+            android:id="@+id/cardView"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="8dp"
+            android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
+            android:layout_marginVertical="@dimen/spacing_micro"
+            android:clickable="true"
+            android:foreground="?android:attr/selectableItemBackground"
+            app:cardCornerRadius="@dimen/spacing_micro"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/infoButton"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent">
+
+            <TextView
+                android:id="@+id/buttonLabel"
+                style="@style/TextAppearance.AppCompat.Medium"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:drawablePadding="@dimen/spacing_normal"
+                android:minLines="2"
+                android:paddingHorizontal="@dimen/padding_normal"
+                android:paddingVertical="@dimen/padding_normal"
+                tools:text="@string/navigation_button_edittext_login_label" />
+        </android.support.v7.widget.CardView>
+
+        <com.example.android.autofillframework.app.InfoButton
+            android:id="@+id/infoButton"
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_gravity="center"
+            android:layout_marginHorizontal="@dimen/spacing_normal"
+            android:background="@android:color/transparent"
+            android:src="@drawable/ic_info_black_24dp"
+            app:dialogText=""
+            app:layout_constraintBottom_toBottomOf="@+id/cardView"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/cardView" />
+    </android.support.constraint.ConstraintLayout>
+</merge>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/virtual_login_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/virtual_login_activity.xml
index 59f56e1..9f49293 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/virtual_login_activity.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/virtual_login_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,35 +13,78 @@
  * 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:weightSum="100">
+<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:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin">
+
+    <TextView
+        android:id="@+id/custom_virtual_login_header"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center"
+        android:text="@string/navigation_button_custom_virtual_view_login_label"
+        app:layout_constraintEnd_toStartOf="@+id/imageButton"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.example.android.autofillframework.app.InfoButton
+        android:id="@+id/imageButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/ic_info_black_24dp"
+        app:layout_constraintBottom_toBottomOf="@+id/custom_virtual_login_header"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/custom_virtual_login_header"
+        app:layout_constraintTop_toTopOf="@+id/custom_virtual_login_header"
+        app:dialogText="@string/custom_virtual_login_info"/>
 
     <com.example.android.autofillframework.app.CustomVirtualView
         android:id="@+id/custom_view"
         android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="50" />
+        android:layout_height="@dimen/custom_view_height"
+        android:layout_marginEnd="8dp"
+        android:layout_marginStart="8dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/custom_virtual_login_header" />
 
-    <LinearLayout
-        android:layout_width="match_parent"
+    <TextView
+        android:id="@+id/clear"
+        style="@style/Widget.AppCompat.Button.Borderless"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
-        android:gravity="center"
-        android:orientation="horizontal">
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:text="@string/clear_label"
+        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/custom_view" />
 
-        <Button
-            android:id="@+id/clear"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Clear" />
-
-        <Button
-            android:id="@+id/login"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Login" />
-    </LinearLayout>
-</LinearLayout>
+    <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/clear"
+        app:layout_constraintTop_toTopOf="@+id/clear" />
+</android.support.constraint.ConstraintLayout>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/welcome_activity.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/welcome_activity.xml
index 4d746c5..4b9c3c9 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/welcome_activity.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/layout/welcome_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,17 +13,25 @@
  * 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="wrap_content"
-             android:layout_height="match_parent"
-             android:paddingBottom="@dimen/activity_vertical_margin"
-             android:paddingLeft="@dimen/activity_horizontal_margin"
-             android:paddingRight="@dimen/activity_horizontal_margin"
-             android:paddingTop="@dimen/activity_vertical_margin">
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:orientation="vertical">
 
     <TextView
-        android:layout_width="match_parent"
+        style="@style/TextAppearance.AppCompat.Large"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
         android:text="@string/welcome_text" />
-</FrameLayout>
\ No newline at end of file
+
+    <TextView
+        android:id="@+id/countdownText"
+        style="@style/TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/spacing_large"
+        android:layout_gravity="center_horizontal" />
+</LinearLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-dimens.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-dimens.xml
deleted file mode 100644
index 22074a2..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-dimens.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-  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/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-styles.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-styles.xml
deleted file mode 100644
index 03d1974..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-  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/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-v11/template-styles.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-v11/template-styles.xml
deleted file mode 100644
index 8c1ea66..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-v11/template-styles.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-  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/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-colors.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-colors.xml
deleted file mode 100644
index 8b6ec3f..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-colors.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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>
-
-
-</resources>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml
deleted file mode 100644
index c778e4f..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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">
-    </style>
-
-</resources>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/xml/autofill_service.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/attrs.xml
similarity index 61%
rename from prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/xml/autofill_service.xml
rename to prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/attrs.xml
index bc026e5..fbc1fb3 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/xml/autofill_service.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/attrs.xml
@@ -14,11 +14,14 @@
  * 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.service.SettingsActivity"/>
\ No newline at end of file
+<resources>
+    <declare-styleable name="NavigationItem">
+        <attr name="labelText" format="string" />
+        <attr name="infoText" format="string" />
+        <attr name="itemLogo" format="integer" />
+        <attr name="imageColor" format="reference" />
+    </declare-styleable>
+    <declare-styleable name="InfoButton">
+        <attr name="dialogText" format="string" />
+    </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/base-strings.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/base-strings.xml
deleted file mode 100644
index ddf8b07..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/base-strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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">AutofillFramework</string>
-    <string name="intro_message">
-        <![CDATA[
-        
-            
-            This sample app demos the Autofill feature introduced in Android O.
-            
-        
-        ]]>
-    </string>
-</resources>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/dimens.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/dimens.xml
index 961725d..0827ef5 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/dimens.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/dimens.xml
@@ -25,4 +25,6 @@
     <dimen name="padding_normal_button">12dp</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="custom_view_height">150dp</dimen>
 </resources>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/strings.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/strings.xml
index b5611ae..46b5349 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/strings.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <!--
  * Copyright (C) 2017 The Android Open Source Project
  *
@@ -16,13 +16,20 @@
 -->
 
 <resources>
+    <string name="app_name">Autofill Sample</string>
     <string name="settings_name">Autofill Settings</string>
+    <string name="navigation_button_custom_virtual_view_login_label">Sample Login Using a Custom Virtual View</string>
+    <string name="navigation_button_spinners_credit_card_label">Sample Credit Card Check Out Using Spinners</string>
+    <string name="navigation_button_edittext_login_label">Sample Login Using EditTexts</string>
+    <string name="navigation_button_autocomplete_login_label">Sample Login Using AutoCompleteTextViews</string>
+    <string name="navigation_button_email_compose_label">Sample Email Compose Using EditTexts</string>
+    <string name="navigation_button_compound_view_credit_card_label">Sample Credit Card Check Out Using Compound Views</string>
     <string name="username_label">Username</string>
     <string name="password_label">Password</string>
-    <string name="welcome_text">You have successfully signed in!</string>
+    <string name="welcome_text">Success!</string>
     <string name="standard_view_sign_in">Sign in using standard views</string>
-    <string name="virtual_view_sign_in">Sign in using virtual views</string>
-    <string name="credit_card_checkout">Credit Card check out</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 Exp</string>
@@ -37,6 +44,7 @@
     </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>
@@ -44,6 +52,53 @@
     <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="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="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.
+    </string>
+    <string name="autocomplete_login_info">This is a sample login page that uses
+        AutoCompleteTextViews instead of EditTexts. The AutoComplete dialogs can potentially
+        interfere with the Autofill dialogs, so it is necessary to implement the AutofillCallback to
+        disable AutoComplete when Autofill is working.
+    </string>
+    <string name="custom_virtual_login_info">This is a sample login page that uses a custom View with
+        virtual children. Since the Autofill framework does not know how to autofill the virtual
+        children out of the box, it is necessary implement certain Autofill-specific methods and
+        interface directly with AutofillManager.
+    </string>
+    <string name="spinners_credit_card_info">This is a sample credit card checkout page that uses
+        EditTexts and Spinners to input data into the form. While EditTexts are optimized out of the
+        box, Spinners can require a small amount of work when using a custom array adapter.
+        In that case, you need to tell the Autofill framework which values in the adapter map to
+        which indices.
+    </string>
+    <string name="email_compose_info">
+        This is a sample email compose page that uses EditTexts to compose the email. Since none of
+        the fields on the page are important to autofill, it is necessary to set the
+        android:importantForAutofill XML property appropriately for each View. You can either set it
+        to &quot;no&quot; on all non-autofillable Views, or set &quot;noExcludeDescendants&quot;
+        on the root View if all Views in the hierarchy should not be autofilled. In this case, we
+        did the latter.
+    </string>
+    <string name="compound_view_credit_card_info">
+        This is a sample credit card checkout page that uses a custom compound View to input the credit
+        card\'s expiration date and an EditText to input the credit card number. While the EditText is
+        optimized out of the box for autofill, this example shows how to implement certain Autofill-
+        specific methods and XML properties for the custom compound view.
+    </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="month_array">
         <item>Jan</item>
         <item>Feb</item>
@@ -92,15 +147,9 @@
         <item>31</item>
     </string-array>
 
-    <string-array name="year_array">
-        <item>2017</item>
-        <item>2018</item>
-        <item>2019</item>
-        <item>2020</item>
-        <item>2021</item>
-        <item>2022</item>
-        <item>2023</item>
-        <item>2024</item>
+    <string-array name="mock_autocomplete_sign_in_suggestions">
+        <item>user-1</item>
+        <item>user-2</item>
     </string-array>
 
 </resources>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/styles.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/styles.xml
index 92aabaa..8fe4718 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/styles.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/styles.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,12 +14,14 @@
  * limitations under the License.
 -->
 <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>
@@ -29,6 +30,7 @@
         <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>
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/template-dimens.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/template-dimens.xml
deleted file mode 100644
index 39e710b..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/template-dimens.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
-  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/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/template-styles.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/template-styles.xml
deleted file mode 100644
index 6e7d593..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/values/template-styles.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-  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/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/xml/multidataset_service.xml
similarity index 94%
copy from prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml
copy to prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/xml/multidataset_service.xml
index bc026e5..0c1c14d 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/xml/autofill_service.xml
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/Application/src/main/res/xml/multidataset_service.xml
@@ -21,4 +21,4 @@
 -->
 <autofill-service
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:settingsActivity="com.example.android.autofillframework.service.SettingsActivity"/>
\ No newline at end of file
+    android:settingsActivity="com.example.android.autofillframework.multidatasetservice.settings.SettingsActivity"/>
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/README.md b/prebuilts/gradle/AutofillFramework/kotlinApp/README.md
index 53e4a7f..282a1ea 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/README.md
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/README.md
@@ -1,63 +1,98 @@
-Android AutofillFramework Sample (Kotlin)
+
+Android AutofillFramework Sample
 ===================================
 
 This sample demonstrates the use of the Autofill Framework. It includes implementations of client
-Activities that want to be autofilled, and a Service that can provide autofill data to client
-Activities. For simplicity, this sample's service uses mock data to autofill what it thinks are
-username and password text fields.
+Activities with views that should be autofilled, and a Service that can provide autofill data to
+client Activities.
 
 Introduction
 ------------
 
 This sample demonstrates the use of the Autofill framework from the service side and the client
-side. In practice, only a small handful of apps will develop Autofill services because a device will
-only have one service as default at a time. However, all apps targeting O with any autofillable
-fields should follow the necessary steps to ensure their Views can be autofilled. Most of the time,
-there is little to no extra code involved, but the use of custom views and views with virtual child
-views requires more work.
+side. In practice, only a small handful of apps will develop Autofill services because a device
+will only have one service as default at a time, and there is just a small number of 3rd-party apps
+providing these services (typically password managers). However, all apps targeting O with any
+autofillable fields should follow the necessary steps to 1) ensure their views can be autofilled
+and 2) optimize their autofill performance. Most of the time, there is little to no extra code
+involved, but the use of custom views and views with virtual child views requires more work.
 
-The sample's Autofill service is implemented to parse the client's view hierarchy in search of text
-fields that it has data for. If such text fields exist in the hierarchy, the service sends data
-suggestions to the client to fill in those text fields. In this basic sample, it will only look for
-views whose resource IDs are "usernameField" and "passwordField" and will send mock credential data
-accordingly. A real Autofill service would attempt to autofill more than just login credentials and
-would be able to fill in other view types in addition to text fields (e.g. spinners, checkboxes,
-etc.). It would also use more advanced heuristics to determine what data to send to which views.
+The sample's Autofill service is implemented to parse the client's view hierarchy in search of
+autofillable fields that it has data for. If such fields exist in the hierarchy, the service sends
+data suggestions to the client to autofill those fields. The client uses the following attributes
+to specify autofill properties: `importantForAutofill`, `autofillHints`, and `autofillType`.
+`importantForAutofill` specifies whether the view is autofillable. `autofillHints` is a list of
+strings that hint to the service **what** data to fill the view with. This sample service only
+supports the hints listed [here](https://developer.android.com/reference/android/view/View.html#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE)
+with the prefix AUTOFILL_HINT_*. `autofillType` tells the service the type of data it expects to
+receive (i.e. a list index, a date, or a string). Specifying `autofillType` is only necessary
+when implementing a custom view since all of the provided widgets in the UI toolkit do this for you.
 
-To set the device's default Autofill service to the one in the sample, edit
-**Settings** > **Apps &amp; Notifications** > **Default Apps** > **Auto-fill app** and select the
-sample app. To edit the service's settings, open the **Autofill Settings** launcher icon. Here, you
-can set whether you want to enable authentication on the entire Autofill Response or just on
-individual datasets. You can also set the number of mock datasets that are sent to the client app.
+To set the device's default Autofill service to the one in the sample, edit **Settings** >
+**System** > **Languages &amp; Input** > **Advanced** > **Auto-fill service** and select the sample
+app. To edit the service's settings, tap the settings icon next to the **Auto-fill service** list
+item or open the **Autofill Settings** launcher icon.. Here, you can set whether you want to enable
+authentication on the entire autofill Response or just on individual autofill datasets. You should
+also set the master password to “unlock” authenticated autofill data with.
 
-The client side of the app has two Activities that each have a username field and a password field.
-One of the Activities uses standard views and the other Activity uses a custom view with virtual
-children. The standard views do not require any extra code to allow autofill. The following code
-example shows the `View` method you have to override in order to provide view hierarchy data to the
-Autofill service. This is triggered when the `View` goes into focus and Android invokes an Autofill
-request.
+**Note:** This sample service stores all autofill data in SharedPreferences and thus is not secure.
+Be careful about what you store when experimenting with the sample because anyone with root access
+to your device will be able to view your autofill data.
 
-```java
-/*
-This method is responsible for building the ViewStructure that gets passed to the AutoFillService
-by the framework when it is time to find Autofill suggestions. To do this, it should traverse
-through its view hierarchy and add views to the ViewStructure on the way.
-*/
-@Override
-public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
-  structure.setClassName(getClass().getName());
-  int childrenSize = mItems.size();
-  int index = structure.addChildCount(childrenSize);
-  for (int i = 0; i < childrenSize; i++) {
-      Item item = mItems.valueAt(i);
-      ViewStructure child = structure.newChild(index, item.id, flags);
-      child.setSanitized(item.sanitized);
-      child.setText(item.text);
-      child.setAutoFillValue(AutoFillValue.forText(item.text));
-      child.setFocused(item.line.focused);
-      child.setId(item.id, getContext().getPackageName(), null, item.line.idEntry);
-      index++;
-  }
+The client side of the app has three Activities that each have autofillable fields. The first
+Activity uses standard views to comprise a login form. Very little needs to be done by the client
+app to ensure the views get autofilled properly. The second Activity uses a custom view with
+virtual children, meaning some autofillable child views are not known to the View hierarchy to be
+child views. Supporting autofill on these child views is a little more involved.
+
+The following code snippet shows how to signal to the autofill service that a specific
+autofillable virtual view has come into focus:
+
+```kotlin
+class CustomVirtualView(context: Context, attrs: AttributeSet) : View(context, attrs) {
+...
+    // Cache AutofillManager system service
+    private val autofillManager: AutofillManager = context.getSystemService(AutofillManager::class.java)
+...
+    // Notify service which virtual view has come into focus.
+    autofillManager.notifyViewEntered(this@CustomVirtualView, id, absBounds)
+...
+    // Notify service that a virtual view has left focus.
+    autofillManager.notifyViewExited(this@CustomVirtualView, id)
+}
+```
+
+Now that the autofillable view has signaled to the service that it has been autofilled, it needs
+to provide the virtual view hierarchy to the Autofill service. This is done out of the box for
+views part of the UI toolkit, but you need to implement this yourself if you have the view has
+virtual child views. The following code example shows the `View` method you have to override in
+order to provide this view hierarchy data to the Autofill service.
+
+```kotlin
+override fun onProvideAutofillVirtualStructure(structure: ViewStructure, flags: Int) {
+    // Build a ViewStructure to pack in AutoFillService requests.
+    structure.setClassName(javaClass.name)
+    val childrenSize = items.size()
+    Log.d(TAG, "onProvideAutofillVirtualStructure(): flags = " + flags + ", items = "
+            + childrenSize + ", extras: " + bundleToString(structure.extras))
+    var 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 (i in 0..childrenSize - 1) {
+        val item = items.valueAt(i)
+        Log.d(TAG, "Adding new child at index $index: $item")
+        val child = structure.newChild(index)
+        child.setAutofillId(structure, item.id)
+        child.setAutofillHints(item.hints)
+        child.setAutofillType(item.type)
+        child.setDataIsSensitive(!item.sanitized)
+        child.text = item.text
+        child.setAutofillValue(AutofillValue.forText(item.text))
+        child.setFocused(item.focused)
+        child.setId(item.id, context.packageName, null, item.line.idEntry)
+        child.setClassName(item.className)
+        index++
+    }
 }
 ```
 
@@ -65,30 +100,29 @@
 (wrapped in a `Response` object), the user can pick which `Dataset` they want to autofill their
 views with. When a `Dataset` is selected, this method is invoked for all of the views that were
 associated with that `Dataset` by the service. For example, the `Dataset` might contain Autofill
-values for username, password, birthday, and address. This method would then be invoked on all four
-of those fields. The following code example shows how the sample app implements the method to
-deliver a UI update to the appropriate child view after the user makes their selection.
+values for username, password, birthday, and address. This method would then be invoked on all
+four of those fields. The following code example shows how the sample app implements the method
+to deliver a UI update to the appropriate child view after the user makes their selection.
 
-```java
-/*
-User has just selected a Dataset from the list of Autofill suggestions and the Dataset's
-AutoFillValue gets passed into this method. This method updates the UI based on the data
-in the AutoFillValue.
-*/
-@Override
-public void autoFillVirtual(int id, AutoFillValue value) {
-  Item item = mItems.get(id);
-  if (item == null) {
-      // ID not recognized so no-op.
-      return;
-  }
-  if (!item.editable) {
-      // Component is not editable so no-op.
-      return;
-  }
-  // Set the virtual child view's text to the text wrapped in the AutoFillValue.
-  item.text = value.getTextValue();
-  postInvalidate();
+```kotlin
+override fun autofill(values: SparseArray<AutofillValue>) {
+    // 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.
+    for (i in 0..values.size() - 1) {
+        val id = values.keyAt(i)
+        val value = values.valueAt(i)
+        items[id]?.let { item ->
+            if (item.editable) {
+                // Set the item's text to the text wrapped in the AutofillValue.
+                item.text = value.textValue
+            } else {
+                // Component not editable, so no-op.
+            }
+        }
+    }
+    postInvalidate()
 }
 ```
 
@@ -96,13 +130,15 @@
 --------------
 
 - Android SDK Preview O
-- Android Build Tools v25.0.3
-- Android Support Repository
+- Android Studio 3.0+
+- Android Build Tools v26+
+- Android Support Repository v26+
+- Gradle v3.0+
 
 Screenshots
 -------------
 
-<img src="screenshots/1_HomePage.png" height="400" alt="Screenshot"/> <img src="screenshots/2_StandardViewAutofillable.png" height="400" alt="Screenshot"/> <img src="screenshots/3_StandardViewAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/4_WelcomeActivity.png" height="400" alt="Screenshot"/> <img src="screenshots/5_CustomViewAutofillable.png" height="400" alt="Screenshot"/> <img src="screenshots/6_CustomViewAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/7_SettingsActivity.png" height="400" alt="Screenshot"/> <img src="screenshots/8_AuthNeeded.png" height="400" alt="Screenshot"/> <img src="screenshots/9_AuthActivity.png" height="400" alt="Screenshot"/> 
+<img src="screenshots/1_MainPage.png" height="400" alt="Screenshot"/> <img src="screenshots/2_SampleLoginEditTexts.png" height="400" alt="Screenshot"/> <img src="screenshots/3_SampleLoginEditTextsAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/4_WelcomeActivity.png" height="400" alt="Screenshot"/> <img src="screenshots/5_SampleLoginCustomVirtualView.png" height="400" alt="Screenshot"/> <img src="screenshots/6_SampleLoginCustomVirtualViewAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/7_SampleCheckOutSpinnersAutofillable.png" height="400" alt="Screenshot"/> <img src="screenshots/8_SampleCheckOutSpinnersAutofilled.png" height="400" alt="Screenshot"/> <img src="screenshots/9_SettingsActivity.png" height="400" alt="Screenshot"/> <img src="screenshots/10_AuthNeeded.png" height="400" alt="Screenshot"/> <img src="screenshots/11_AuthActivity.png" height="400" alt="Screenshot"/> 
 
 Getting Started
 ---------------
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/build.gradle b/prebuilts/gradle/AutofillFramework/kotlinApp/build.gradle
index e69de29..6fc4282 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/build.gradle
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/build.gradle
@@ -0,0 +1,22 @@
+buildscript {
+    repositories {
+        jcenter()
+        maven {
+            url 'https://maven.google.com'
+        }
+    }
+    ext.kotlin_version = '1.1.4-3'
+    dependencies {
+        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+allprojects {
+    repositories {
+        jcenter()
+        maven {
+            url 'https://maven.google.com'
+        }
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/AutofillFramework/kotlinApp/gradle/wrapper/gradle-wrapper.properties
index eaba301..cb80c87 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/gradle/wrapper/gradle-wrapper.properties
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Apr 10 15:27:10 PDT 2013
+#Mon Jul 31 13:11:55 PDT 2017
 distributionBase=GRADLE_USER_HOME
 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.1-milestone-1-all.zip
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/10_AuthNeeded.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/10_AuthNeeded.png
new file mode 100644
index 0000000..6b7e18c
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/10_AuthNeeded.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/11_AuthActivity.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/11_AuthActivity.png
new file mode 100644
index 0000000..f2665ee
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/11_AuthActivity.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/1_HomePage.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/1_HomePage.png
deleted file mode 100644
index edb54ee..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/1_HomePage.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/1_MainPage.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/1_MainPage.png
new file mode 100644
index 0000000..2e45ca0
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/1_MainPage.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/2_SampleLoginEditTexts.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/2_SampleLoginEditTexts.png
new file mode 100644
index 0000000..14b014b
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/2_SampleLoginEditTexts.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/2_StandardViewAutofillable.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/2_StandardViewAutofillable.png
deleted file mode 100644
index cce8642..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/2_StandardViewAutofillable.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/3_SampleLoginEditTextsAutofilled.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/3_SampleLoginEditTextsAutofilled.png
new file mode 100644
index 0000000..240e38a
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/3_SampleLoginEditTextsAutofilled.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/3_StandardViewAutofilled.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/3_StandardViewAutofilled.png
deleted file mode 100644
index b53efa0..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/3_StandardViewAutofilled.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/4_WelcomeActivity.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/4_WelcomeActivity.png
index 1d61a55..1e22bf5 100644
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/4_WelcomeActivity.png
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/4_WelcomeActivity.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/5_CustomViewAutofillable.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/5_CustomViewAutofillable.png
deleted file mode 100644
index 7e0895b..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/5_CustomViewAutofillable.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/5_SampleLoginCustomVirtualView.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/5_SampleLoginCustomVirtualView.png
new file mode 100644
index 0000000..aef77d9
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/5_SampleLoginCustomVirtualView.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/6_CustomViewAutofilled.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/6_CustomViewAutofilled.png
deleted file mode 100644
index 793816e..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/6_CustomViewAutofilled.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/6_SampleLoginCustomVirtualViewAutofilled.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/6_SampleLoginCustomVirtualViewAutofilled.png
new file mode 100644
index 0000000..a13ce13
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/6_SampleLoginCustomVirtualViewAutofilled.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/7_SampleCheckOutSpinnersAutofillable.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/7_SampleCheckOutSpinnersAutofillable.png
new file mode 100644
index 0000000..bbd6e5b
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/7_SampleCheckOutSpinnersAutofillable.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/7_SettingsActivity.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/7_SettingsActivity.png
deleted file mode 100644
index 187c0b3..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/7_SettingsActivity.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/8_AuthNeeded.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/8_AuthNeeded.png
deleted file mode 100644
index e3b4f92..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/8_AuthNeeded.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/8_SampleCheckOutSpinnersAutofilled.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/8_SampleCheckOutSpinnersAutofilled.png
new file mode 100644
index 0000000..b5c15cc
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/8_SampleCheckOutSpinnersAutofilled.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/9_AuthActivity.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/9_AuthActivity.png
deleted file mode 100644
index 905193e..0000000
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/9_AuthActivity.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/9_SettingsActivity.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/9_SettingsActivity.png
new file mode 100644
index 0000000..7ee47bb
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/9_SettingsActivity.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/icon-web.png b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/icon-web.png
old mode 100644
new mode 100755
index 29fb3ff..b64a676
--- a/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/icon-web.png
+++ b/prebuilts/gradle/AutofillFramework/kotlinApp/screenshots/icon-web.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/10_AuthNeeded.png b/prebuilts/gradle/AutofillFramework/screenshots/10_AuthNeeded.png
new file mode 100644
index 0000000..6b7e18c
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/10_AuthNeeded.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/11_AuthActivity.png b/prebuilts/gradle/AutofillFramework/screenshots/11_AuthActivity.png
new file mode 100644
index 0000000..f2665ee
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/11_AuthActivity.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/1_HomePage.png b/prebuilts/gradle/AutofillFramework/screenshots/1_HomePage.png
deleted file mode 100644
index edb54ee..0000000
--- a/prebuilts/gradle/AutofillFramework/screenshots/1_HomePage.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/1_MainPage.png b/prebuilts/gradle/AutofillFramework/screenshots/1_MainPage.png
new file mode 100644
index 0000000..2e45ca0
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/1_MainPage.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/2_SampleLoginEditTexts.png b/prebuilts/gradle/AutofillFramework/screenshots/2_SampleLoginEditTexts.png
new file mode 100644
index 0000000..14b014b
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/2_SampleLoginEditTexts.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/2_StandardViewAutofillable.png b/prebuilts/gradle/AutofillFramework/screenshots/2_StandardViewAutofillable.png
deleted file mode 100644
index cce8642..0000000
--- a/prebuilts/gradle/AutofillFramework/screenshots/2_StandardViewAutofillable.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/3_SampleLoginEditTextsAutofilled.png b/prebuilts/gradle/AutofillFramework/screenshots/3_SampleLoginEditTextsAutofilled.png
new file mode 100644
index 0000000..240e38a
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/3_SampleLoginEditTextsAutofilled.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/3_StandardViewAutofilled.png b/prebuilts/gradle/AutofillFramework/screenshots/3_StandardViewAutofilled.png
deleted file mode 100644
index b53efa0..0000000
--- a/prebuilts/gradle/AutofillFramework/screenshots/3_StandardViewAutofilled.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/4_WelcomeActivity.png b/prebuilts/gradle/AutofillFramework/screenshots/4_WelcomeActivity.png
index 1d61a55..1e22bf5 100644
--- a/prebuilts/gradle/AutofillFramework/screenshots/4_WelcomeActivity.png
+++ b/prebuilts/gradle/AutofillFramework/screenshots/4_WelcomeActivity.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/5_CustomViewAutofillable.png b/prebuilts/gradle/AutofillFramework/screenshots/5_CustomViewAutofillable.png
deleted file mode 100644
index 7e0895b..0000000
--- a/prebuilts/gradle/AutofillFramework/screenshots/5_CustomViewAutofillable.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/5_SampleLoginCustomVirtualView.png b/prebuilts/gradle/AutofillFramework/screenshots/5_SampleLoginCustomVirtualView.png
new file mode 100644
index 0000000..aef77d9
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/5_SampleLoginCustomVirtualView.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/6_CustomViewAutofilled.png b/prebuilts/gradle/AutofillFramework/screenshots/6_CustomViewAutofilled.png
deleted file mode 100644
index 793816e..0000000
--- a/prebuilts/gradle/AutofillFramework/screenshots/6_CustomViewAutofilled.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/6_SampleLoginCustomVirtualViewAutofilled.png b/prebuilts/gradle/AutofillFramework/screenshots/6_SampleLoginCustomVirtualViewAutofilled.png
new file mode 100644
index 0000000..a13ce13
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/6_SampleLoginCustomVirtualViewAutofilled.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/7_SampleCheckOutSpinnersAutofillable.png b/prebuilts/gradle/AutofillFramework/screenshots/7_SampleCheckOutSpinnersAutofillable.png
new file mode 100644
index 0000000..bbd6e5b
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/7_SampleCheckOutSpinnersAutofillable.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/7_SettingsActivity.png b/prebuilts/gradle/AutofillFramework/screenshots/7_SettingsActivity.png
deleted file mode 100644
index 187c0b3..0000000
--- a/prebuilts/gradle/AutofillFramework/screenshots/7_SettingsActivity.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/8_AuthNeeded.png b/prebuilts/gradle/AutofillFramework/screenshots/8_AuthNeeded.png
deleted file mode 100644
index e3b4f92..0000000
--- a/prebuilts/gradle/AutofillFramework/screenshots/8_AuthNeeded.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/8_SampleCheckOutSpinnersAutofilled.png b/prebuilts/gradle/AutofillFramework/screenshots/8_SampleCheckOutSpinnersAutofilled.png
new file mode 100644
index 0000000..b5c15cc
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/8_SampleCheckOutSpinnersAutofilled.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/9_AuthActivity.png b/prebuilts/gradle/AutofillFramework/screenshots/9_AuthActivity.png
deleted file mode 100644
index 905193e..0000000
--- a/prebuilts/gradle/AutofillFramework/screenshots/9_AuthActivity.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/9_SettingsActivity.png b/prebuilts/gradle/AutofillFramework/screenshots/9_SettingsActivity.png
new file mode 100644
index 0000000..7ee47bb
--- /dev/null
+++ b/prebuilts/gradle/AutofillFramework/screenshots/9_SettingsActivity.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/screenshots/icon-web.png b/prebuilts/gradle/AutofillFramework/screenshots/icon-web.png
old mode 100644
new mode 100755
index 29fb3ff..b64a676
--- a/prebuilts/gradle/AutofillFramework/screenshots/icon-web.png
+++ b/prebuilts/gradle/AutofillFramework/screenshots/icon-web.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/settings.gradle b/prebuilts/gradle/AutofillFramework/settings.gradle
index 0a5c310..9464a35 100644
--- a/prebuilts/gradle/AutofillFramework/settings.gradle
+++ b/prebuilts/gradle/AutofillFramework/settings.gradle
@@ -1,2 +1 @@
-
 include 'Application'
diff --git a/prebuilts/gradle/BasicAccessibility/Application/build.gradle b/prebuilts/gradle/BasicAccessibility/Application/build.gradle
index 3c9428a..271193c 100644
--- a/prebuilts/gradle/BasicAccessibility/Application/build.gradle
+++ b/prebuilts/gradle/BasicAccessibility/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 11
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicAccessibility/README.md b/prebuilts/gradle/BasicAccessibility/README.md
index d70843b..9584216 100644
--- a/prebuilts/gradle/BasicAccessibility/README.md
+++ b/prebuilts/gradle/BasicAccessibility/README.md
@@ -20,8 +20,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicAndroidKeyStore/Application/build.gradle b/prebuilts/gradle/BasicAndroidKeyStore/Application/build.gradle
index 60de968..43e4f90 100644
--- a/prebuilts/gradle/BasicAndroidKeyStore/Application/build.gradle
+++ b/prebuilts/gradle/BasicAndroidKeyStore/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicAndroidKeyStore/README.md b/prebuilts/gradle/BasicAndroidKeyStore/README.md
index 440161d..21e8208 100644
--- a/prebuilts/gradle/BasicAndroidKeyStore/README.md
+++ b/prebuilts/gradle/BasicAndroidKeyStore/README.md
@@ -30,8 +30,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicContactables/Application/build.gradle b/prebuilts/gradle/BasicContactables/Application/build.gradle
index eb72362..3d2b388 100644
--- a/prebuilts/gradle/BasicContactables/Application/build.gradle
+++ b/prebuilts/gradle/BasicContactables/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,8 +34,10 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/BasicContactables/README.md b/prebuilts/gradle/BasicContactables/README.md
index 47cf273..5784763 100644
--- a/prebuilts/gradle/BasicContactables/README.md
+++ b/prebuilts/gradle/BasicContactables/README.md
@@ -25,8 +25,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicGestureDetect/Application/build.gradle b/prebuilts/gradle/BasicGestureDetect/Application/build.gradle
index 60de968..43e4f90 100644
--- a/prebuilts/gradle/BasicGestureDetect/Application/build.gradle
+++ b/prebuilts/gradle/BasicGestureDetect/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicGestureDetect/README.md b/prebuilts/gradle/BasicGestureDetect/README.md
index 096a309..3edbcb1 100644
--- a/prebuilts/gradle/BasicGestureDetect/README.md
+++ b/prebuilts/gradle/BasicGestureDetect/README.md
@@ -24,8 +24,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicImmersiveMode/Application/build.gradle b/prebuilts/gradle/BasicImmersiveMode/Application/build.gradle
index 19aaade..1728dc8 100644
--- a/prebuilts/gradle/BasicImmersiveMode/Application/build.gradle
+++ b/prebuilts/gradle/BasicImmersiveMode/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 19
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicImmersiveMode/README.md b/prebuilts/gradle/BasicImmersiveMode/README.md
index 57cd70a..55e7b40 100644
--- a/prebuilts/gradle/BasicImmersiveMode/README.md
+++ b/prebuilts/gradle/BasicImmersiveMode/README.md
@@ -19,8 +19,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicManagedProfile/Application/build.gradle b/prebuilts/gradle/BasicManagedProfile/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/BasicManagedProfile/Application/build.gradle
+++ b/prebuilts/gradle/BasicManagedProfile/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicManagedProfile/README.md b/prebuilts/gradle/BasicManagedProfile/README.md
index 776d3c3..d293ccb 100644
--- a/prebuilts/gradle/BasicManagedProfile/README.md
+++ b/prebuilts/gradle/BasicManagedProfile/README.md
@@ -38,8 +38,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicMediaDecoder/Application/build.gradle b/prebuilts/gradle/BasicMediaDecoder/Application/build.gradle
index 0f78dbd..ead34cd 100644
--- a/prebuilts/gradle/BasicMediaDecoder/Application/build.gradle
+++ b/prebuilts/gradle/BasicMediaDecoder/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 17
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicMediaDecoder/README.md b/prebuilts/gradle/BasicMediaDecoder/README.md
index c5c5446..1341d6d 100644
--- a/prebuilts/gradle/BasicMediaDecoder/README.md
+++ b/prebuilts/gradle/BasicMediaDecoder/README.md
@@ -54,8 +54,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicMediaRouter/Application/build.gradle b/prebuilts/gradle/BasicMediaRouter/Application/build.gradle
index 0f78dbd..ead34cd 100644
--- a/prebuilts/gradle/BasicMediaRouter/Application/build.gradle
+++ b/prebuilts/gradle/BasicMediaRouter/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 17
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicMediaRouter/README.md b/prebuilts/gradle/BasicMediaRouter/README.md
index b16d67b..90566a9 100644
--- a/prebuilts/gradle/BasicMediaRouter/README.md
+++ b/prebuilts/gradle/BasicMediaRouter/README.md
@@ -14,8 +14,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/BasicMultitouch/Application/build.gradle b/prebuilts/gradle/BasicMultitouch/Application/build.gradle
index 9ecb73a..a0b2858 100644
--- a/prebuilts/gradle/BasicMultitouch/Application/build.gradle
+++ b/prebuilts/gradle/BasicMultitouch/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 8
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicMultitouch/README.md b/prebuilts/gradle/BasicMultitouch/README.md
index c6dc682..750adc3 100644
--- a/prebuilts/gradle/BasicMultitouch/README.md
+++ b/prebuilts/gradle/BasicMultitouch/README.md
@@ -29,8 +29,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicNetworking/Application/build.gradle b/prebuilts/gradle/BasicNetworking/Application/build.gradle
index 12dcfb1..43f4041 100644
--- a/prebuilts/gradle/BasicNetworking/Application/build.gradle
+++ b/prebuilts/gradle/BasicNetworking/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicNetworking/README.md b/prebuilts/gradle/BasicNetworking/README.md
index ecc234a..ff1df31 100644
--- a/prebuilts/gradle/BasicNetworking/README.md
+++ b/prebuilts/gradle/BasicNetworking/README.md
@@ -22,8 +22,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicNotifications/Application/build.gradle b/prebuilts/gradle/BasicNotifications/Application/build.gradle
index 9ecb73a..a0b2858 100644
--- a/prebuilts/gradle/BasicNotifications/Application/build.gradle
+++ b/prebuilts/gradle/BasicNotifications/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 8
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicNotifications/README.md b/prebuilts/gradle/BasicNotifications/README.md
index 31ec5ec..4ba4216 100644
--- a/prebuilts/gradle/BasicNotifications/README.md
+++ b/prebuilts/gradle/BasicNotifications/README.md
@@ -53,8 +53,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicRenderScript/Application/build.gradle b/prebuilts/gradle/BasicRenderScript/Application/build.gradle
index ed8cbb1..e27b918 100644
--- a/prebuilts/gradle/BasicRenderScript/Application/build.gradle
+++ b/prebuilts/gradle/BasicRenderScript/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile files('renderscript-v8.jar')
 }
 
@@ -32,12 +35,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 8
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicRenderScript/README.md b/prebuilts/gradle/BasicRenderScript/README.md
index 594a227..46be845 100644
--- a/prebuilts/gradle/BasicRenderScript/README.md
+++ b/prebuilts/gradle/BasicRenderScript/README.md
@@ -28,8 +28,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicSyncAdapter/Application/build.gradle b/prebuilts/gradle/BasicSyncAdapter/Application/build.gradle
index 12dcfb1..43f4041 100644
--- a/prebuilts/gradle/BasicSyncAdapter/Application/build.gradle
+++ b/prebuilts/gradle/BasicSyncAdapter/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicSyncAdapter/README.md b/prebuilts/gradle/BasicSyncAdapter/README.md
index 5d41cfe..5ea7280 100644
--- a/prebuilts/gradle/BasicSyncAdapter/README.md
+++ b/prebuilts/gradle/BasicSyncAdapter/README.md
@@ -28,8 +28,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BasicTransition/Application/build.gradle b/prebuilts/gradle/BasicTransition/Application/build.gradle
index 19aaade..1728dc8 100644
--- a/prebuilts/gradle/BasicTransition/Application/build.gradle
+++ b/prebuilts/gradle/BasicTransition/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 19
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BasicTransition/README.md b/prebuilts/gradle/BasicTransition/README.md
index 8a350ce..d7defb7 100644
--- a/prebuilts/gradle/BasicTransition/README.md
+++ b/prebuilts/gradle/BasicTransition/README.md
@@ -33,8 +33,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BatchStepSensor/Application/build.gradle b/prebuilts/gradle/BatchStepSensor/Application/build.gradle
index 19aaade..1728dc8 100644
--- a/prebuilts/gradle/BatchStepSensor/Application/build.gradle
+++ b/prebuilts/gradle/BatchStepSensor/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 19
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BatchStepSensor/README.md b/prebuilts/gradle/BatchStepSensor/README.md
index 61a365d..81515ee 100644
--- a/prebuilts/gradle/BatchStepSensor/README.md
+++ b/prebuilts/gradle/BatchStepSensor/README.md
@@ -31,8 +31,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BeamLargeFiles/Application/build.gradle b/prebuilts/gradle/BeamLargeFiles/Application/build.gradle
index ddee143..7473a10 100644
--- a/prebuilts/gradle/BeamLargeFiles/Application/build.gradle
+++ b/prebuilts/gradle/BeamLargeFiles/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 16
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BeamLargeFiles/README.md b/prebuilts/gradle/BeamLargeFiles/README.md
index 7283c0b..ddcea6d 100644
--- a/prebuilts/gradle/BeamLargeFiles/README.md
+++ b/prebuilts/gradle/BeamLargeFiles/README.md
@@ -15,8 +15,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/BluetoothAdvertisements/Application/build.gradle b/prebuilts/gradle/BluetoothAdvertisements/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/BluetoothAdvertisements/Application/build.gradle
+++ b/prebuilts/gradle/BluetoothAdvertisements/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BluetoothAdvertisements/README.md b/prebuilts/gradle/BluetoothAdvertisements/README.md
index 1882fc1..625b2d7 100644
--- a/prebuilts/gradle/BluetoothAdvertisements/README.md
+++ b/prebuilts/gradle/BluetoothAdvertisements/README.md
@@ -29,8 +29,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BluetoothChat/Application/build.gradle b/prebuilts/gradle/BluetoothChat/Application/build.gradle
index 3c9428a..271193c 100644
--- a/prebuilts/gradle/BluetoothChat/Application/build.gradle
+++ b/prebuilts/gradle/BluetoothChat/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 11
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BluetoothChat/README.md b/prebuilts/gradle/BluetoothChat/README.md
index f668c90..77f2e27 100644
--- a/prebuilts/gradle/BluetoothChat/README.md
+++ b/prebuilts/gradle/BluetoothChat/README.md
@@ -32,8 +32,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BluetoothLeGatt/Application/build.gradle b/prebuilts/gradle/BluetoothLeGatt/Application/build.gradle
index 60de968..43e4f90 100644
--- a/prebuilts/gradle/BluetoothLeGatt/Application/build.gradle
+++ b/prebuilts/gradle/BluetoothLeGatt/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BluetoothLeGatt/README.md b/prebuilts/gradle/BluetoothLeGatt/README.md
index 6478cf7..96eb7c5 100644
--- a/prebuilts/gradle/BluetoothLeGatt/README.md
+++ b/prebuilts/gradle/BluetoothLeGatt/README.md
@@ -23,8 +23,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/BorderlessButtons/Application/build.gradle b/prebuilts/gradle/BorderlessButtons/Application/build.gradle
index e81066a..9267a5e 100644
--- a/prebuilts/gradle/BorderlessButtons/Application/build.gradle
+++ b/prebuilts/gradle/BorderlessButtons/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 14
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/BorderlessButtons/README.md b/prebuilts/gradle/BorderlessButtons/README.md
index aed198c..9463955 100644
--- a/prebuilts/gradle/BorderlessButtons/README.md
+++ b/prebuilts/gradle/BorderlessButtons/README.md
@@ -24,8 +24,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Camera2Basic/Application/build.gradle b/prebuilts/gradle/Camera2Basic/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/Camera2Basic/Application/build.gradle
+++ b/prebuilts/gradle/Camera2Basic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java b/prebuilts/gradle/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
index a29fa14..aca77f7 100644
--- a/prebuilts/gradle/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
+++ b/prebuilts/gradle/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 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.
@@ -20,8 +20,6 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.Fragment;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.pm.PackageManager;
@@ -47,7 +45,9 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.support.annotation.NonNull;
-import android.support.v13.app.FragmentCompat;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.Fragment;
 import android.support.v4.content.ContextCompat;
 import android.util.Log;
 import android.util.Size;
@@ -72,7 +72,7 @@
 import java.util.concurrent.TimeUnit;
 
 public class Camera2BasicFragment extends Fragment
-        implements View.OnClickListener, FragmentCompat.OnRequestPermissionsResultCallback {
+        implements View.OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback {
 
     /**
      * Conversion from screen rotation to JPEG orientation.
@@ -461,11 +461,10 @@
     }
 
     private void requestCameraPermission() {
-        if (FragmentCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
+        if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
             new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
         } else {
-            FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
-                    REQUEST_CAMERA_PERMISSION);
+            requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
         }
     }
 
@@ -488,6 +487,7 @@
      * @param width  The width of available size for camera preview
      * @param height The height of available size for camera preview
      */
+    @SuppressWarnings("SuspiciousNameCombination")
     private void setUpCameraOutputs(int width, int height) {
         Activity activity = getActivity();
         CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
@@ -842,6 +842,7 @@
             };
 
             mCaptureSession.stopRepeating();
+            mCaptureSession.abortCaptures();
             mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
         } catch (CameraAccessException e) {
             e.printStackTrace();
@@ -924,7 +925,7 @@
          */
         private final File mFile;
 
-        public ImageSaver(Image image, File file) {
+        ImageSaver(Image image, File file) {
             mImage = image;
             mFile = file;
         }
@@ -983,6 +984,7 @@
             return dialog;
         }
 
+        @NonNull
         @Override
         public Dialog onCreateDialog(Bundle savedInstanceState) {
             final Activity activity = getActivity();
@@ -1004,6 +1006,7 @@
      */
     public static class ConfirmationDialog extends DialogFragment {
 
+        @NonNull
         @Override
         public Dialog onCreateDialog(Bundle savedInstanceState) {
             final Fragment parent = getParentFragment();
@@ -1012,8 +1015,7 @@
                     .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialog, int which) {
-                            FragmentCompat.requestPermissions(parent,
-                                    new String[]{Manifest.permission.CAMERA},
+                            parent.requestPermissions(new String[]{Manifest.permission.CAMERA},
                                     REQUEST_CAMERA_PERMISSION);
                         }
                     })
diff --git a/prebuilts/gradle/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/CameraActivity.java b/prebuilts/gradle/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/CameraActivity.java
index eb7f834..fab28dd 100644
--- a/prebuilts/gradle/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/CameraActivity.java
+++ b/prebuilts/gradle/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/CameraActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 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.
@@ -16,17 +16,17 @@
 
 package com.example.android.camera2basic;
 
-import android.app.Activity;
 import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
 
-public class CameraActivity extends Activity {
+public class CameraActivity extends AppCompatActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_camera);
         if (null == savedInstanceState) {
-            getFragmentManager().beginTransaction()
+            getSupportFragmentManager().beginTransaction()
                     .replace(R.id.container, Camera2BasicFragment.newInstance())
                     .commit();
         }
diff --git a/prebuilts/gradle/Camera2Basic/Application/src/main/res/values/styles.xml b/prebuilts/gradle/Camera2Basic/Application/src/main/res/values/styles.xml
index 3f3bdfb..b76b27d 100644
--- a/prebuilts/gradle/Camera2Basic/Application/src/main/res/values/styles.xml
+++ b/prebuilts/gradle/Camera2Basic/Application/src/main/res/values/styles.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?><!--
- Copyright 2014 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.
@@ -14,5 +14,7 @@
  limitations under the License.
 -->
 <resources>
-    <style name="MaterialTheme" parent="android:Theme.Material.Light.NoActionBar.Fullscreen" />
+    <style name="MaterialTheme" parent="Theme.AppCompat.Light.NoActionBar">
+        <item name="android:windowFullscreen">true</item>
+    </style>
 </resources>
diff --git a/prebuilts/gradle/Camera2Basic/README.md b/prebuilts/gradle/Camera2Basic/README.md
index 2bf96ea..0dc7529 100644
--- a/prebuilts/gradle/Camera2Basic/README.md
+++ b/prebuilts/gradle/Camera2Basic/README.md
@@ -42,8 +42,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Camera2Raw/Application/build.gradle b/prebuilts/gradle/Camera2Raw/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/Camera2Raw/Application/build.gradle
+++ b/prebuilts/gradle/Camera2Raw/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/Camera2Raw/README.md b/prebuilts/gradle/Camera2Raw/README.md
index 18b394f..a110bc7 100644
--- a/prebuilts/gradle/Camera2Raw/README.md
+++ b/prebuilts/gradle/Camera2Raw/README.md
@@ -26,8 +26,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Camera2Video/Application/build.gradle b/prebuilts/gradle/Camera2Video/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/Camera2Video/Application/build.gradle
+++ b/prebuilts/gradle/Camera2Video/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/Camera2Video/README.md b/prebuilts/gradle/Camera2Video/README.md
index 2434503..ec8ec0c 100644
--- a/prebuilts/gradle/Camera2Video/README.md
+++ b/prebuilts/gradle/Camera2Video/README.md
@@ -43,8 +43,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/CardEmulation/Application/build.gradle b/prebuilts/gradle/CardEmulation/Application/build.gradle
index 19aaade..1728dc8 100644
--- a/prebuilts/gradle/CardEmulation/Application/build.gradle
+++ b/prebuilts/gradle/CardEmulation/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 19
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/CardEmulation/README.md b/prebuilts/gradle/CardEmulation/README.md
index d3a7452..c293a0f 100644
--- a/prebuilts/gradle/CardEmulation/README.md
+++ b/prebuilts/gradle/CardEmulation/README.md
@@ -12,8 +12,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/CardReader/Application/build.gradle b/prebuilts/gradle/CardReader/Application/build.gradle
index 19aaade..1728dc8 100644
--- a/prebuilts/gradle/CardReader/Application/build.gradle
+++ b/prebuilts/gradle/CardReader/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 19
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/CardReader/README.md b/prebuilts/gradle/CardReader/README.md
index 016fdd4..eeddeb6 100644
--- a/prebuilts/gradle/CardReader/README.md
+++ b/prebuilts/gradle/CardReader/README.md
@@ -13,8 +13,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/CardView/Application/build.gradle b/prebuilts/gradle/CardView/Application/build.gradle
index ed07cff..096ee9c 100644
--- a/prebuilts/gradle/CardView/Application/build.gradle
+++ b/prebuilts/gradle/CardView/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,6 +13,9 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
@@ -28,12 +31,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/CardView/README.md b/prebuilts/gradle/CardView/README.md
index 92c752e..041030d 100644
--- a/prebuilts/gradle/CardView/README.md
+++ b/prebuilts/gradle/CardView/README.md
@@ -8,8 +8,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/ClippingBasic/Application/build.gradle b/prebuilts/gradle/ClippingBasic/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/ClippingBasic/Application/build.gradle
+++ b/prebuilts/gradle/ClippingBasic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ClippingBasic/README.md b/prebuilts/gradle/ClippingBasic/README.md
index 76bb91f..c5e9fee 100644
--- a/prebuilts/gradle/ClippingBasic/README.md
+++ b/prebuilts/gradle/ClippingBasic/README.md
@@ -47,8 +47,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/CommitContentSampleApp/README.md b/prebuilts/gradle/CommitContentSampleApp/README.md
index 6e10c6e..22ce72c 100644
--- a/prebuilts/gradle/CommitContentSampleApp/README.md
+++ b/prebuilts/gradle/CommitContentSampleApp/README.md
@@ -27,8 +27,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/CommitContentSampleIME/README.md b/prebuilts/gradle/CommitContentSampleIME/README.md
index 6875e47..86da7c7 100644
--- a/prebuilts/gradle/CommitContentSampleIME/README.md
+++ b/prebuilts/gradle/CommitContentSampleIME/README.md
@@ -32,8 +32,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ConfirmCredential/Application/build.gradle b/prebuilts/gradle/ConfirmCredential/Application/build.gradle
index cdcf106..2ad233b 100644
--- a/prebuilts/gradle/ConfirmCredential/Application/build.gradle
+++ b/prebuilts/gradle/ConfirmCredential/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 23
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ConfirmCredential/README.md b/prebuilts/gradle/ConfirmCredential/README.md
index 4746aa4..0f988f4 100644
--- a/prebuilts/gradle/ConfirmCredential/README.md
+++ b/prebuilts/gradle/ConfirmCredential/README.md
@@ -30,8 +30,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ContentProviderPaging/README.md b/prebuilts/gradle/ContentProviderPaging/README.md
index 54a7c69..a818223 100644
--- a/prebuilts/gradle/ContentProviderPaging/README.md
+++ b/prebuilts/gradle/ContentProviderPaging/README.md
@@ -27,8 +27,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ContentProviderPaging/common.gradle b/prebuilts/gradle/ContentProviderPaging/common.gradle
index c1cfce0..e5c3bdd 100644
--- a/prebuilts/gradle/ContentProviderPaging/common.gradle
+++ b/prebuilts/gradle/ContentProviderPaging/common.gradle
@@ -1,13 +1,13 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 'android-O'
-    buildToolsVersion "25.0.2"
+    compileSdkVersion 26
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         applicationId "com.example.android.contentproviderpaging"
-        minSdkVersion 'O'
-        targetSdkVersion 'O'
+        minSdkVersion 26
+        targetSdkVersion 26
     }
 
     buildTypes {
diff --git a/prebuilts/gradle/ContentProviderPaging/kotlinApp/common.gradle b/prebuilts/gradle/ContentProviderPaging/kotlinApp/common.gradle
index c1cfce0..e5c3bdd 100644
--- a/prebuilts/gradle/ContentProviderPaging/kotlinApp/common.gradle
+++ b/prebuilts/gradle/ContentProviderPaging/kotlinApp/common.gradle
@@ -1,13 +1,13 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 'android-O'
-    buildToolsVersion "25.0.2"
+    compileSdkVersion 26
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         applicationId "com.example.android.contentproviderpaging"
-        minSdkVersion 'O'
-        targetSdkVersion 'O'
+        minSdkVersion 26
+        targetSdkVersion 26
     }
 
     buildTypes {
diff --git a/prebuilts/gradle/CustomChoiceList/Application/build.gradle b/prebuilts/gradle/CustomChoiceList/Application/build.gradle
index 12dcfb1..43f4041 100644
--- a/prebuilts/gradle/CustomChoiceList/Application/build.gradle
+++ b/prebuilts/gradle/CustomChoiceList/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/CustomChoiceList/README.md b/prebuilts/gradle/CustomChoiceList/README.md
index fcbd403..3e0c58e 100644
--- a/prebuilts/gradle/CustomChoiceList/README.md
+++ b/prebuilts/gradle/CustomChoiceList/README.md
@@ -41,8 +41,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/CustomNotifications/Application/build.gradle b/prebuilts/gradle/CustomNotifications/Application/build.gradle
index ddee143..7473a10 100644
--- a/prebuilts/gradle/CustomNotifications/Application/build.gradle
+++ b/prebuilts/gradle/CustomNotifications/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 16
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/CustomNotifications/README.md b/prebuilts/gradle/CustomNotifications/README.md
index e861c4c..62751d5 100644
--- a/prebuilts/gradle/CustomNotifications/README.md
+++ b/prebuilts/gradle/CustomNotifications/README.md
@@ -25,8 +25,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/CustomTransition/Application/build.gradle b/prebuilts/gradle/CustomTransition/Application/build.gradle
index 19aaade..1728dc8 100644
--- a/prebuilts/gradle/CustomTransition/Application/build.gradle
+++ b/prebuilts/gradle/CustomTransition/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 19
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/CustomTransition/README.md b/prebuilts/gradle/CustomTransition/README.md
index 7422170..b8f2419 100644
--- a/prebuilts/gradle/CustomTransition/README.md
+++ b/prebuilts/gradle/CustomTransition/README.md
@@ -32,8 +32,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DataLayer/Application/build.gradle b/prebuilts/gradle/DataLayer/Application/build.gradle
index 2ab2620..64d0ff0 100644
--- a/prebuilts/gradle/DataLayer/Application/build.gradle
+++ b/prebuilts/gradle/DataLayer/Application/build.gradle
@@ -19,12 +19,12 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     wearApp project(':Wearable')
 }
 
@@ -38,9 +38,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/DataLayer/README.md b/prebuilts/gradle/DataLayer/README.md
index 3f567f4..f13caff 100644
--- a/prebuilts/gradle/DataLayer/README.md
+++ b/prebuilts/gradle/DataLayer/README.md
@@ -27,8 +27,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DataLayer/Wearable/build.gradle b/prebuilts/gradle/DataLayer/Wearable/build.gradle
index c393601..968e76c 100644
--- a/prebuilts/gradle/DataLayer/Wearable/build.gradle
+++ b/prebuilts/gradle/DataLayer/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/DelayedConfirmation/Application/build.gradle b/prebuilts/gradle/DelayedConfirmation/Application/build.gradle
index 49b1770..ddfdc08 100644
--- a/prebuilts/gradle/DelayedConfirmation/Application/build.gradle
+++ b/prebuilts/gradle/DelayedConfirmation/Application/build.gradle
@@ -19,12 +19,12 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     wearApp project(':Wearable')
 }
 
@@ -38,9 +38,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/DelayedConfirmation/README.md b/prebuilts/gradle/DelayedConfirmation/README.md
index 8421f64..a55e483 100644
--- a/prebuilts/gradle/DelayedConfirmation/README.md
+++ b/prebuilts/gradle/DelayedConfirmation/README.md
@@ -12,8 +12,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/DelayedConfirmation/Wearable/build.gradle b/prebuilts/gradle/DelayedConfirmation/Wearable/build.gradle
index e00b0d4..4e2a9d9 100644
--- a/prebuilts/gradle/DelayedConfirmation/Wearable/build.gradle
+++ b/prebuilts/gradle/DelayedConfirmation/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/DeviceOwner/Application/build.gradle b/prebuilts/gradle/DeviceOwner/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/DeviceOwner/Application/build.gradle
+++ b/prebuilts/gradle/DeviceOwner/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/DeviceOwner/README.md b/prebuilts/gradle/DeviceOwner/README.md
index 8123821..1003384 100644
--- a/prebuilts/gradle/DeviceOwner/README.md
+++ b/prebuilts/gradle/DeviceOwner/README.md
@@ -30,8 +30,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DirectBoot/Application/build.gradle b/prebuilts/gradle/DirectBoot/Application/build.gradle
index 25fdcba..30ce397 100644
--- a/prebuilts/gradle/DirectBoot/Application/build.gradle
+++ b/prebuilts/gradle/DirectBoot/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.android.support:recyclerview-v7:25.0.1'
     compile 'com.android.support:design:25.0.1'
 }
@@ -33,8 +36,10 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 25
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 24
diff --git a/prebuilts/gradle/DirectBoot/README.md b/prebuilts/gradle/DirectBoot/README.md
index 4496375..fc3836e 100644
--- a/prebuilts/gradle/DirectBoot/README.md
+++ b/prebuilts/gradle/DirectBoot/README.md
@@ -44,7 +44,7 @@
 --------------
 
 - Android SDK 25
-- Android Build Tools v25.0.3
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DirectShare/Application/build.gradle b/prebuilts/gradle/DirectShare/Application/build.gradle
index cdcf106..2ad233b 100644
--- a/prebuilts/gradle/DirectShare/Application/build.gradle
+++ b/prebuilts/gradle/DirectShare/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 23
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/DirectShare/README.md b/prebuilts/gradle/DirectShare/README.md
index ed23137..499777e 100644
--- a/prebuilts/gradle/DirectShare/README.md
+++ b/prebuilts/gradle/DirectShare/README.md
@@ -28,8 +28,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DirectorySelection/Application/build.gradle b/prebuilts/gradle/DirectorySelection/Application/build.gradle
index 4cead15..fb2b4c6 100644
--- a/prebuilts/gradle/DirectorySelection/Application/build.gradle
+++ b/prebuilts/gradle/DirectorySelection/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.android.support:recyclerview-v7:+'
 }
 
@@ -32,12 +35,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/DirectorySelection/README.md b/prebuilts/gradle/DirectorySelection/README.md
index f746eb5..83df6c3 100644
--- a/prebuilts/gradle/DirectorySelection/README.md
+++ b/prebuilts/gradle/DirectorySelection/README.md
@@ -107,8 +107,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DisplayingBitmaps/Application/build.gradle b/prebuilts/gradle/DisplayingBitmaps/Application/build.gradle
index 5d9af9d..8b982b7 100644
--- a/prebuilts/gradle/DisplayingBitmaps/Application/build.gradle
+++ b/prebuilts/gradle/DisplayingBitmaps/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,8 +34,10 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 9
diff --git a/prebuilts/gradle/DisplayingBitmaps/README.md b/prebuilts/gradle/DisplayingBitmaps/README.md
index a0c07b5..9c50b56 100644
--- a/prebuilts/gradle/DisplayingBitmaps/README.md
+++ b/prebuilts/gradle/DisplayingBitmaps/README.md
@@ -20,8 +20,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DocumentCentricApps/Application/build.gradle b/prebuilts/gradle/DocumentCentricApps/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/DocumentCentricApps/Application/build.gradle
+++ b/prebuilts/gradle/DocumentCentricApps/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/DocumentCentricApps/README.md b/prebuilts/gradle/DocumentCentricApps/README.md
index 25e1a06..d206103 100644
--- a/prebuilts/gradle/DocumentCentricApps/README.md
+++ b/prebuilts/gradle/DocumentCentricApps/README.md
@@ -25,8 +25,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DocumentCentricRelinquishIdentity/Application/build.gradle b/prebuilts/gradle/DocumentCentricRelinquishIdentity/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/DocumentCentricRelinquishIdentity/Application/build.gradle
+++ b/prebuilts/gradle/DocumentCentricRelinquishIdentity/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/DocumentCentricRelinquishIdentity/README.md b/prebuilts/gradle/DocumentCentricRelinquishIdentity/README.md
index e915d97..3202cb9 100644
--- a/prebuilts/gradle/DocumentCentricRelinquishIdentity/README.md
+++ b/prebuilts/gradle/DocumentCentricRelinquishIdentity/README.md
@@ -7,8 +7,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/DoneBar/Application/build.gradle b/prebuilts/gradle/DoneBar/Application/build.gradle
index e81066a..9267a5e 100644
--- a/prebuilts/gradle/DoneBar/Application/build.gradle
+++ b/prebuilts/gradle/DoneBar/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 14
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/DoneBar/README.md b/prebuilts/gradle/DoneBar/README.md
index b267e99..788fe5c 100644
--- a/prebuilts/gradle/DoneBar/README.md
+++ b/prebuilts/gradle/DoneBar/README.md
@@ -31,8 +31,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DownloadableFonts/.google/packaging.yaml b/prebuilts/gradle/DownloadableFonts/.google/packaging.yaml
index dd9814f..b8cb5c8 100644
--- a/prebuilts/gradle/DownloadableFonts/.google/packaging.yaml
+++ b/prebuilts/gradle/DownloadableFonts/.google/packaging.yaml
@@ -6,7 +6,7 @@
 ---
 status:       PUBLISHED
 technologies: [Android]
-categories:   [UI, Android O Preview]
+categories:   [UI]
 languages:    [Java]
 solutions:    [Mobile]
 github:       android-DownloadableFonts
diff --git a/prebuilts/gradle/DownloadableFonts/README.md b/prebuilts/gradle/DownloadableFonts/README.md
index b88821d..0cdbb54 100644
--- a/prebuilts/gradle/DownloadableFonts/README.md
+++ b/prebuilts/gradle/DownloadableFonts/README.md
@@ -63,22 +63,14 @@
 </application>
 ```
 
-Note that the sample uses Google Play Services as a font provider, which requires pre-released
-version of Google Play Services.
-You can sign up for the beta program so that the beta version of Google Play Services is
-downloaded to your device. https://developers.google.com/android/guides/beta-program
-If you have Google Play Services whose version number is equal or above 11.x.x, that means you
-have the compatible version installed. (You can confirm by navigating to
-Settings -> Apps -> Google Play Services)
-
 [1]: https://developer.android.com/reference/android/support/v4/provider/FontRequest.html
 [2]: https://developer.android.com/reference/android/support/v4/provider/FontsContractCompat.html
 
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DownloadableFonts/app/build.gradle b/prebuilts/gradle/DownloadableFonts/app/build.gradle
index 203427e..80c6aa8 100644
--- a/prebuilts/gradle/DownloadableFonts/app/build.gradle
+++ b/prebuilts/gradle/DownloadableFonts/app/build.gradle
@@ -1,16 +1,17 @@
 apply plugin: 'com.android.application'
 
+ext {
+    supportLibVersion = '26.0.1'
+}
+
 android {
-    compileSdkVersion 'android-O'
-    buildToolsVersion "26.0.0 rc2"
+    compileSdkVersion 26
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         applicationId "com.example.android.downloadablefonts"
-        // Once API level 26 SDK is launched, lower the minSdkVersion.
-        // At this moment, an app targeting the preview version of the SDK only runs on the
-        // preview device.
-        minSdkVersion 'O'
-        targetSdkVersion 'O'
+        minSdkVersion 14
+        targetSdkVersion 26
     }
 
     buildTypes {
@@ -21,8 +22,8 @@
     }
 
     dependencies {
-        compile 'com.android.support:appcompat-v7:26.0.0-beta1'
-        compile 'com.android.support:design:26.0.0-beta1'
-        compile 'com.android.support:cardview-v7:26.0.0-beta1'
+        compile "com.android.support:appcompat-v7:$supportLibVersion"
+        compile "com.android.support:design:$supportLibVersion"
+        compile "com.android.support:cardview-v7:$supportLibVersion"
     }
 }
diff --git a/prebuilts/gradle/DownloadableFonts/app/src/main/res/layout/bottom_sheet_font_query.xml b/prebuilts/gradle/DownloadableFonts/app/src/main/res/layout/bottom_sheet_font_query.xml
index c30193c..2d8f2be 100644
--- a/prebuilts/gradle/DownloadableFonts/app/src/main/res/layout/bottom_sheet_font_query.xml
+++ b/prebuilts/gradle/DownloadableFonts/app/src/main/res/layout/bottom_sheet_font_query.xml
@@ -47,7 +47,8 @@
 
                 <android.support.design.widget.TextInputLayout
                     android:id="@+id/auto_complete_family_name_input"
-                    android:layout_width="240dp"
+                    android:layout_width="0dp"
+                    android:layout_weight="4"
                     android:layout_height="wrap_content">
 
                     <AutoCompleteTextView
@@ -66,6 +67,7 @@
 
                 <Button
                     android:id="@+id/button_request"
+                    android:layout_weight="1"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:text="@string/request" />
@@ -108,6 +110,7 @@
                         android:layout_height="wrap_content"
                         android:layout_width="80dp"
                         android:layout_marginStart="@dimen/margin_small"
+                        android:layout_marginLeft="@dimen/margin_small"
                         android:textSize="16sp"
                         android:gravity="end" />
                 </LinearLayout>
@@ -149,6 +152,7 @@
                         android:layout_height="wrap_content"
                         android:layout_width="80dp"
                         android:layout_marginStart="@dimen/margin_small"
+                        android:layout_marginLeft="@dimen/margin_small"
                         android:textSize="16sp"
                         android:gravity="end" />
                 </LinearLayout>
@@ -190,6 +194,7 @@
                         android:layout_height="wrap_content"
                         android:layout_width="80dp"
                         android:layout_marginStart="@dimen/margin_small"
+                        android:layout_marginLeft="@dimen/margin_small"
                         android:textSize="16sp"
                         android:gravity="end" />
                 </LinearLayout>
diff --git a/prebuilts/gradle/DownloadableFonts/build.gradle b/prebuilts/gradle/DownloadableFonts/build.gradle
index 0d7c5de..b0fce9c 100644
--- a/prebuilts/gradle/DownloadableFonts/build.gradle
+++ b/prebuilts/gradle/DownloadableFonts/build.gradle
@@ -2,15 +2,17 @@
 buildscript {
     repositories {
         jcenter()
+        google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.4.0-alpha6'
+        classpath 'com.android.tools.build:gradle:3.0.0-alpha9'
     }
 }
 
 allprojects {
     repositories {
         jcenter()
+        google()
     }
 }
 
diff --git a/prebuilts/gradle/DownloadableFonts/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/DownloadableFonts/gradle/wrapper/gradle-wrapper.properties
index 9eaab7c..fa419a3 100644
--- a/prebuilts/gradle/DownloadableFonts/gradle/wrapper/gradle-wrapper.properties
+++ b/prebuilts/gradle/DownloadableFonts/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed May 10 17:45:17 JST 2017
+#Wed Aug 09 11:54:51 JST 2017
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-4.0-20170406000015+0000-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip
diff --git a/prebuilts/gradle/DownloadableFonts/kotlinApp/app/build.gradle b/prebuilts/gradle/DownloadableFonts/kotlinApp/app/build.gradle
index 1d94fb0..46db5c9 100644
--- a/prebuilts/gradle/DownloadableFonts/kotlinApp/app/build.gradle
+++ b/prebuilts/gradle/DownloadableFonts/kotlinApp/app/build.gradle
@@ -1,17 +1,18 @@
 apply plugin: 'com.android.application'
 apply plugin: 'kotlin-android'
 
+ext {
+    supportLibVersion = '26.0.1'
+}
+
 android {
-    compileSdkVersion 'android-O'
-    buildToolsVersion "26.0.0 rc2"
+    compileSdkVersion 26
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         applicationId "com.example.android.downloadablefonts"
-        // Once API level 26 SDK is launched, lower the minSdkVersion.
-        // At this moment, an app targeting the preview version of the SDK only runs on the
-        // preview device.
-        minSdkVersion 'O'
-        targetSdkVersion 'O'
+        minSdkVersion 14
+        targetSdkVersion 26
     }
 
     buildTypes {
@@ -22,9 +23,9 @@
     }
 
     dependencies {
-        compile 'com.android.support:appcompat-v7:26.0.0-beta1'
-        compile 'com.android.support:design:26.0.0-beta1'
-        compile 'com.android.support:cardview-v7:26.0.0-beta1'
+        compile "com.android.support:appcompat-v7:$supportLibVersion"
+        compile "com.android.support:design:$supportLibVersion"
+        compile "com.android.support:cardview-v7:$supportLibVersion"
     }
 }
 
diff --git a/prebuilts/gradle/DownloadableFonts/kotlinApp/app/src/main/kotlin/com/example/android/downloadablefonts/QueryBuilder.kt b/prebuilts/gradle/DownloadableFonts/kotlinApp/app/src/main/kotlin/com/example/android/downloadablefonts/QueryBuilder.kt
index 1f6f679..bcc50a4 100644
--- a/prebuilts/gradle/DownloadableFonts/kotlinApp/app/src/main/kotlin/com/example/android/downloadablefonts/QueryBuilder.kt
+++ b/prebuilts/gradle/DownloadableFonts/kotlinApp/app/src/main/kotlin/com/example/android/downloadablefonts/QueryBuilder.kt
@@ -31,18 +31,10 @@
         }
         val builder = StringBuilder()
         builder.append("name=").append(familyName)
-        if (weight != null) {
-            builder.append("&weight=").append(weight)
-        }
-        if (width != null) {
-            builder.append("&width=").append(width)
-        }
-        if (italic != null) {
-            builder.append("&italic=").append(italic)
-        }
-        if (besteffort != null) {
-            builder.append("&besteffort=").append(besteffort)
-        }
+        weight?.let { builder.append("&weight=").append(weight) }
+        width?.let { builder.append("&width=").append(width) }
+        italic?.let { builder.append("&italic=").append(italic) }
+        besteffort?.let { builder.append("&besteffort=").append(besteffort) }
         return builder.toString()
     }
 }
diff --git a/prebuilts/gradle/DownloadableFonts/kotlinApp/app/src/main/res/layout/bottom_sheet_font_query.xml b/prebuilts/gradle/DownloadableFonts/kotlinApp/app/src/main/res/layout/bottom_sheet_font_query.xml
index c30193c..2d8f2be 100644
--- a/prebuilts/gradle/DownloadableFonts/kotlinApp/app/src/main/res/layout/bottom_sheet_font_query.xml
+++ b/prebuilts/gradle/DownloadableFonts/kotlinApp/app/src/main/res/layout/bottom_sheet_font_query.xml
@@ -47,7 +47,8 @@
 
                 <android.support.design.widget.TextInputLayout
                     android:id="@+id/auto_complete_family_name_input"
-                    android:layout_width="240dp"
+                    android:layout_width="0dp"
+                    android:layout_weight="4"
                     android:layout_height="wrap_content">
 
                     <AutoCompleteTextView
@@ -66,6 +67,7 @@
 
                 <Button
                     android:id="@+id/button_request"
+                    android:layout_weight="1"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:text="@string/request" />
@@ -108,6 +110,7 @@
                         android:layout_height="wrap_content"
                         android:layout_width="80dp"
                         android:layout_marginStart="@dimen/margin_small"
+                        android:layout_marginLeft="@dimen/margin_small"
                         android:textSize="16sp"
                         android:gravity="end" />
                 </LinearLayout>
@@ -149,6 +152,7 @@
                         android:layout_height="wrap_content"
                         android:layout_width="80dp"
                         android:layout_marginStart="@dimen/margin_small"
+                        android:layout_marginLeft="@dimen/margin_small"
                         android:textSize="16sp"
                         android:gravity="end" />
                 </LinearLayout>
@@ -190,6 +194,7 @@
                         android:layout_height="wrap_content"
                         android:layout_width="80dp"
                         android:layout_marginStart="@dimen/margin_small"
+                        android:layout_marginLeft="@dimen/margin_small"
                         android:textSize="16sp"
                         android:gravity="end" />
                 </LinearLayout>
diff --git a/prebuilts/gradle/DownloadableFonts/kotlinApp/build.gradle b/prebuilts/gradle/DownloadableFonts/kotlinApp/build.gradle
index d2924b7..138d54e 100644
--- a/prebuilts/gradle/DownloadableFonts/kotlinApp/build.gradle
+++ b/prebuilts/gradle/DownloadableFonts/kotlinApp/build.gradle
@@ -1,11 +1,12 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 buildscript {
-    ext.kotlin_version = '1.1.2-4'
+    ext.kotlin_version = '1.1.3-2'
     repositories {
         jcenter()
+        google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.4.0-alpha6'
+        classpath 'com.android.tools.build:gradle:3.0.0-alpha9'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
@@ -13,6 +14,7 @@
 allprojects {
     repositories {
         jcenter()
+        google()
     }
 }
 
diff --git a/prebuilts/gradle/DragAndDropAcrossApps/README.md b/prebuilts/gradle/DragAndDropAcrossApps/README.md
index dbee0c3..e5a7c77 100644
--- a/prebuilts/gradle/DragAndDropAcrossApps/README.md
+++ b/prebuilts/gradle/DragAndDropAcrossApps/README.md
@@ -50,8 +50,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/DrawableTinting/Application/build.gradle b/prebuilts/gradle/DrawableTinting/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/DrawableTinting/Application/build.gradle
+++ b/prebuilts/gradle/DrawableTinting/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/DrawableTinting/README.md b/prebuilts/gradle/DrawableTinting/README.md
index 6ab1b32..2327a6e 100644
--- a/prebuilts/gradle/DrawableTinting/README.md
+++ b/prebuilts/gradle/DrawableTinting/README.md
@@ -16,8 +16,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/ElevationBasic/Application/build.gradle b/prebuilts/gradle/ElevationBasic/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/ElevationBasic/Application/build.gradle
+++ b/prebuilts/gradle/ElevationBasic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ElevationBasic/README.md b/prebuilts/gradle/ElevationBasic/README.md
index 7fa870d..26f3e8d 100644
--- a/prebuilts/gradle/ElevationBasic/README.md
+++ b/prebuilts/gradle/ElevationBasic/README.md
@@ -41,8 +41,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ElevationDrag/Application/build.gradle b/prebuilts/gradle/ElevationDrag/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/ElevationDrag/Application/build.gradle
+++ b/prebuilts/gradle/ElevationDrag/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ElevationDrag/README.md b/prebuilts/gradle/ElevationDrag/README.md
index 17e617b..ac017c5 100644
--- a/prebuilts/gradle/ElevationDrag/README.md
+++ b/prebuilts/gradle/ElevationDrag/README.md
@@ -24,8 +24,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ElizaChat/Application/build.gradle b/prebuilts/gradle/ElizaChat/Application/build.gradle
index 312518e..88ce6ad 100644
--- a/prebuilts/gradle/ElizaChat/Application/build.gradle
+++ b/prebuilts/gradle/ElizaChat/Application/build.gradle
@@ -19,10 +19,10 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -35,9 +35,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/ElizaChat/README.md b/prebuilts/gradle/ElizaChat/README.md
index e5a630a..771fe59 100644
--- a/prebuilts/gradle/ElizaChat/README.md
+++ b/prebuilts/gradle/ElizaChat/README.md
@@ -67,8 +67,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/EmojiCompat/README.md b/prebuilts/gradle/EmojiCompat/README.md
index e326b15..6ae78cc 100644
--- a/prebuilts/gradle/EmojiCompat/README.md
+++ b/prebuilts/gradle/EmojiCompat/README.md
@@ -95,8 +95,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/EmojiCompat/app/build.gradle b/prebuilts/gradle/EmojiCompat/app/build.gradle
index fec4dab..4867afc 100644
--- a/prebuilts/gradle/EmojiCompat/app/build.gradle
+++ b/prebuilts/gradle/EmojiCompat/app/build.gradle
@@ -17,16 +17,16 @@
 apply plugin: 'com.android.application'
 
 ext {
-    supportLibVersion = '26.0.0-beta1'
+    supportLibVersion = '26.0.0'
 }
 
 android {
-    compileSdkVersion 'android-O'
-    buildToolsVersion "26.0.0-rc1"
+    compileSdkVersion 26
+    buildToolsVersion "26.0.0"
     defaultConfig {
         applicationId "com.example.android.emojicompat"
-        minSdkVersion 'O'
-        targetSdkVersion 'O'
+        minSdkVersion 19
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -51,5 +51,5 @@
 
     // Test
     testCompile 'junit:junit:4.12'
-    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
+    androidTestCompile 'com.android.support.test.espresso:espresso-core:3.0.0'
 }
diff --git a/prebuilts/gradle/EmojiCompat/app/src/main/java/com/example/android/emojicompat/MainActivity.java b/prebuilts/gradle/EmojiCompat/app/src/main/java/com/example/android/emojicompat/MainActivity.java
index 2ef3702..2f93c54 100644
--- a/prebuilts/gradle/EmojiCompat/app/src/main/java/com/example/android/emojicompat/MainActivity.java
+++ b/prebuilts/gradle/EmojiCompat/app/src/main/java/com/example/android/emojicompat/MainActivity.java
@@ -16,11 +16,14 @@
 
 package com.example.android.emojicompat;
 
+import android.content.Context;
 import android.os.Bundle;
 import android.support.text.emoji.EmojiCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.widget.TextView;
 
+import java.lang.ref.WeakReference;
+
 
 public class MainActivity extends AppCompatActivity {
 
@@ -51,18 +54,32 @@
 
         // Regular TextView without EmojiCompat support; you have to manually process the text
         final TextView regularTextView = findViewById(R.id.regular_text_view);
-        EmojiCompat.get().registerInitCallback(new EmojiCompat.InitCallback() {
-            @Override
-            public void onInitialized() {
-                final EmojiCompat compat = EmojiCompat.get();
-                regularTextView.setText(
-                        compat.process(getString(R.string.regular_text_view, EMOJI)));
-            }
-        });
+        EmojiCompat.get().registerInitCallback(new InitCallback(regularTextView));
 
         // Custom TextView
         final TextView customTextView = findViewById(R.id.emoji_custom_text_view);
         customTextView.setText(getString(R.string.custom_text_view, EMOJI));
     }
 
+    private static class InitCallback extends EmojiCompat.InitCallback {
+
+        private final WeakReference<TextView> mRegularTextViewRef;
+
+        InitCallback(TextView regularTextView) {
+            mRegularTextViewRef = new WeakReference<>(regularTextView);
+        }
+
+        @Override
+        public void onInitialized() {
+            final TextView regularTextView = mRegularTextViewRef.get();
+            if (regularTextView != null) {
+                final EmojiCompat compat = EmojiCompat.get();
+                final Context context = regularTextView.getContext();
+                regularTextView.setText(
+                        compat.process(context.getString(R.string.regular_text_view, EMOJI)));
+            }
+        }
+
+    }
+
 }
diff --git a/prebuilts/gradle/EmojiCompat/build.gradle b/prebuilts/gradle/EmojiCompat/build.gradle
index 23afe73..c87685a 100644
--- a/prebuilts/gradle/EmojiCompat/build.gradle
+++ b/prebuilts/gradle/EmojiCompat/build.gradle
@@ -19,13 +19,14 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.4.0-alpha6'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
 allprojects {
     repositories {
         jcenter()
+        google()
     }
 }
 
diff --git a/prebuilts/gradle/EmojiCompat/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/EmojiCompat/gradle/wrapper/gradle-wrapper.properties
index dbde6ba..93a1579 100644
--- a/prebuilts/gradle/EmojiCompat/gradle/wrapper/gradle-wrapper.properties
+++ b/prebuilts/gradle/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-3.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-all.zip
diff --git a/prebuilts/gradle/EmojiCompat/kotlinApp/app/build.gradle b/prebuilts/gradle/EmojiCompat/kotlinApp/app/build.gradle
index af061cd..de2074b 100644
--- a/prebuilts/gradle/EmojiCompat/kotlinApp/app/build.gradle
+++ b/prebuilts/gradle/EmojiCompat/kotlinApp/app/build.gradle
@@ -16,7 +16,7 @@
 
 buildscript {
     ext {
-        kotlin_version = '1.1.2-3'
+        kotlin_version = '1.1.3-2'
     }
     repositories {
         jcenter()
@@ -30,16 +30,16 @@
 apply plugin: 'kotlin-android'
 
 ext {
-    supportLibVersion = '26.0.0-beta1'
+    supportLibVersion = '26.0.0'
 }
 
 android {
-    compileSdkVersion 'android-O'
-    buildToolsVersion "26.0.0-rc1"
+    compileSdkVersion 26
+    buildToolsVersion '26.0.0'
     defaultConfig {
         applicationId "com.example.android.emojicompat"
-        minSdkVersion 'O'
-        targetSdkVersion 'O'
+        minSdkVersion 19
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
diff --git a/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/CustomTextView.kt b/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/CustomTextView.kt
index 3da4e11..dccf739 100644
--- a/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/CustomTextView.kt
+++ b/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/CustomTextView.kt
@@ -38,6 +38,19 @@
 
     private var mEmojiTextViewHelper: EmojiTextViewHelper? = null
 
+    /**
+     * Returns the [EmojiTextViewHelper] for this TextView.
+     *
+     * This property can be called from super constructors through [#setFilters] or [#setAllCaps].
+     */
+    private val emojiTextViewHelper: EmojiTextViewHelper
+        get() {
+            if (mEmojiTextViewHelper == null) {
+                mEmojiTextViewHelper = EmojiTextViewHelper(this)
+            }
+            return mEmojiTextViewHelper as EmojiTextViewHelper
+        }
+
     init {
         emojiTextViewHelper.updateTransformationMethod()
     }
@@ -51,18 +64,4 @@
         emojiTextViewHelper.setAllCaps(allCaps)
     }
 
-    /**
-     * Returns the [EmojiTextViewHelper] for this TextView.
-
-     *
-     * This property can be called from super constructors through [#setFilters] or [#setAllCaps].
-     */
-    private val emojiTextViewHelper: EmojiTextViewHelper
-        get() {
-            if (mEmojiTextViewHelper == null) {
-                mEmojiTextViewHelper = EmojiTextViewHelper(this)
-            }
-            return mEmojiTextViewHelper as EmojiTextViewHelper
-        }
-
 }
diff --git a/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/EmojiCompatApplication.kt b/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/EmojiCompatApplication.kt
index 3f03de0..f51a945 100644
--- a/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/EmojiCompatApplication.kt
+++ b/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/EmojiCompatApplication.kt
@@ -29,6 +29,15 @@
  */
 class EmojiCompatApplication : Application() {
 
+    companion object {
+
+        private val TAG = "EmojiCompatApplication"
+
+        /** Change this to `false` when you want to use the downloadable Emoji font.  */
+        private val USE_BUNDLED_EMOJI = true
+
+    }
+
     override fun onCreate() {
         super.onCreate()
 
@@ -58,12 +67,4 @@
         EmojiCompat.init(config)
     }
 
-    companion object {
-
-        private val TAG = "EmojiCompatApplication"
-
-        /** Change this to `false` when you want to use the downloadable Emoji font.  */
-        private val USE_BUNDLED_EMOJI = true
-    }
-
 }
diff --git a/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/MainActivity.kt b/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/MainActivity.kt
index 7cc9033..b23c800 100644
--- a/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/MainActivity.kt
+++ b/prebuilts/gradle/EmojiCompat/kotlinApp/app/src/main/java/com/example/android/emojicompat/MainActivity.kt
@@ -20,6 +20,7 @@
 import android.support.text.emoji.EmojiCompat
 import android.support.v7.app.AppCompatActivity
 import android.widget.TextView
+import java.lang.ref.WeakReference
 
 
 class MainActivity : AppCompatActivity() {
@@ -53,16 +54,27 @@
 
         // Regular TextView without EmojiCompat support; you have to manually process the text
         val regularTextView: TextView = findViewById(R.id.regular_text_view)
-        EmojiCompat.get().registerInitCallback(object : EmojiCompat.InitCallback() {
-            override fun onInitialized() {
-                val compat = EmojiCompat.get()
-                regularTextView.text = compat.process(getString(R.string.regular_text_view, EMOJI))
-            }
-        })
+        EmojiCompat.get().registerInitCallback(InitCallback(regularTextView))
 
         // Custom TextView
         val customTextView: TextView = findViewById(R.id.emoji_custom_text_view)
         customTextView.text = getString(R.string.custom_text_view, EMOJI)
     }
 
+    private class InitCallback(regularTextView: TextView) : EmojiCompat.InitCallback() {
+
+        val regularTextViewRef = WeakReference(regularTextView)
+
+        override fun onInitialized() {
+            val regularTextView = regularTextViewRef.get()
+            if (regularTextView != null) {
+                val compat = EmojiCompat.get()
+                val context = regularTextView.context
+                regularTextView.text = compat.process(
+                        context.getString(R.string.regular_text_view, EMOJI))
+            }
+        }
+
+    }
+
 }
diff --git a/prebuilts/gradle/EmojiCompat/kotlinApp/build.gradle b/prebuilts/gradle/EmojiCompat/kotlinApp/build.gradle
index 87011ae..f25c0d2 100644
--- a/prebuilts/gradle/EmojiCompat/kotlinApp/build.gradle
+++ b/prebuilts/gradle/EmojiCompat/kotlinApp/build.gradle
@@ -19,13 +19,14 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.4.0-alpha6'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
 allprojects {
     repositories {
         jcenter()
+        google()
     }
 }
 
diff --git a/prebuilts/gradle/EmojiCompat/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/EmojiCompat/kotlinApp/gradle/wrapper/gradle-wrapper.properties
index dbde6ba..93a1579 100644
--- a/prebuilts/gradle/EmojiCompat/kotlinApp/gradle/wrapper/gradle-wrapper.properties
+++ b/prebuilts/gradle/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-3.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-all.zip
diff --git a/prebuilts/gradle/FindMyPhone/Application/build.gradle b/prebuilts/gradle/FindMyPhone/Application/build.gradle
index 49b1770..ddfdc08 100644
--- a/prebuilts/gradle/FindMyPhone/Application/build.gradle
+++ b/prebuilts/gradle/FindMyPhone/Application/build.gradle
@@ -19,12 +19,12 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     wearApp project(':Wearable')
 }
 
@@ -38,9 +38,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/FindMyPhone/README.md b/prebuilts/gradle/FindMyPhone/README.md
index 1947c6c..38412ec 100644
--- a/prebuilts/gradle/FindMyPhone/README.md
+++ b/prebuilts/gradle/FindMyPhone/README.md
@@ -10,8 +10,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/FindMyPhone/Wearable/build.gradle b/prebuilts/gradle/FindMyPhone/Wearable/build.gradle
index e00b0d4..4e2a9d9 100644
--- a/prebuilts/gradle/FindMyPhone/Wearable/build.gradle
+++ b/prebuilts/gradle/FindMyPhone/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/FingerprintDialog/Application/build.gradle b/prebuilts/gradle/FingerprintDialog/Application/build.gradle
index 6301437..9851804 100644
--- a/prebuilts/gradle/FingerprintDialog/Application/build.gradle
+++ b/prebuilts/gradle/FingerprintDialog/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,8 +34,10 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 24
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 24
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 23
diff --git a/prebuilts/gradle/FingerprintDialog/README.md b/prebuilts/gradle/FingerprintDialog/README.md
index 23204aa..850374e 100644
--- a/prebuilts/gradle/FingerprintDialog/README.md
+++ b/prebuilts/gradle/FingerprintDialog/README.md
@@ -36,7 +36,7 @@
 --------------
 
 - Android SDK 24
-- Android Build Tools v25.0.3
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Flashlight/README.md b/prebuilts/gradle/Flashlight/README.md
index c2d7d03..4009db5 100644
--- a/prebuilts/gradle/Flashlight/README.md
+++ b/prebuilts/gradle/Flashlight/README.md
@@ -18,8 +18,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Flashlight/Wearable/build.gradle b/prebuilts/gradle/Flashlight/Wearable/build.gradle
index e00b0d4..4e2a9d9 100644
--- a/prebuilts/gradle/Flashlight/Wearable/build.gradle
+++ b/prebuilts/gradle/Flashlight/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/FloatingActionButtonBasic/Application/build.gradle b/prebuilts/gradle/FloatingActionButtonBasic/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/FloatingActionButtonBasic/Application/build.gradle
+++ b/prebuilts/gradle/FloatingActionButtonBasic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/FloatingActionButtonBasic/README.md b/prebuilts/gradle/FloatingActionButtonBasic/README.md
index bd27f03..1413f58 100644
--- a/prebuilts/gradle/FloatingActionButtonBasic/README.md
+++ b/prebuilts/gradle/FloatingActionButtonBasic/README.md
@@ -25,8 +25,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Geofencing/Application/build.gradle b/prebuilts/gradle/Geofencing/Application/build.gradle
index 7cd3bdc..a607259 100644
--- a/prebuilts/gradle/Geofencing/Application/build.gradle
+++ b/prebuilts/gradle/Geofencing/Application/build.gradle
@@ -19,13 +19,13 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
-    compile 'com.google.android.gms:play-services-location:10.2.4'
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
+    compile 'com.google.android.gms:play-services-location:11.4.0'
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     wearApp project(':Wearable')
 }
 
@@ -39,9 +39,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/Geofencing/README.md b/prebuilts/gradle/Geofencing/README.md
index 7837d68..749b103 100644
--- a/prebuilts/gradle/Geofencing/README.md
+++ b/prebuilts/gradle/Geofencing/README.md
@@ -36,8 +36,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Geofencing/Wearable/build.gradle b/prebuilts/gradle/Geofencing/Wearable/build.gradle
index e00b0d4..4e2a9d9 100644
--- a/prebuilts/gradle/Geofencing/Wearable/build.gradle
+++ b/prebuilts/gradle/Geofencing/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/GridViewPager/README.md b/prebuilts/gradle/GridViewPager/README.md
index 90524c4..a3011a5 100644
--- a/prebuilts/gradle/GridViewPager/README.md
+++ b/prebuilts/gradle/GridViewPager/README.md
@@ -7,8 +7,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/GridViewPager/Wearable/build.gradle b/prebuilts/gradle/GridViewPager/Wearable/build.gradle
index d1db5d1..eafbc95 100644
--- a/prebuilts/gradle/GridViewPager/Wearable/build.gradle
+++ b/prebuilts/gradle/GridViewPager/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/HdrViewfinder/Application/build.gradle b/prebuilts/gradle/HdrViewfinder/Application/build.gradle
index 13e50ee..5e6d269 100644
--- a/prebuilts/gradle/HdrViewfinder/Application/build.gradle
+++ b/prebuilts/gradle/HdrViewfinder/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.android.support:design:24.0.0'
 }
 
@@ -32,12 +35,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/HdrViewfinder/README.md b/prebuilts/gradle/HdrViewfinder/README.md
index aec33ce..1a45882 100644
--- a/prebuilts/gradle/HdrViewfinder/README.md
+++ b/prebuilts/gradle/HdrViewfinder/README.md
@@ -43,8 +43,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/HorizontalPaging/Application/build.gradle b/prebuilts/gradle/HorizontalPaging/Application/build.gradle
index 3c9428a..271193c 100644
--- a/prebuilts/gradle/HorizontalPaging/Application/build.gradle
+++ b/prebuilts/gradle/HorizontalPaging/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 11
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/HorizontalPaging/README.md b/prebuilts/gradle/HorizontalPaging/README.md
index d4f20cf..1a91fa8 100644
--- a/prebuilts/gradle/HorizontalPaging/README.md
+++ b/prebuilts/gradle/HorizontalPaging/README.md
@@ -30,8 +30,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ImmersiveMode/Application/build.gradle b/prebuilts/gradle/ImmersiveMode/Application/build.gradle
index 3c9428a..271193c 100644
--- a/prebuilts/gradle/ImmersiveMode/Application/build.gradle
+++ b/prebuilts/gradle/ImmersiveMode/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 11
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ImmersiveMode/README.md b/prebuilts/gradle/ImmersiveMode/README.md
index 8dd1017..8c67159 100644
--- a/prebuilts/gradle/ImmersiveMode/README.md
+++ b/prebuilts/gradle/ImmersiveMode/README.md
@@ -9,8 +9,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/Interpolator/Application/build.gradle b/prebuilts/gradle/Interpolator/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/Interpolator/Application/build.gradle
+++ b/prebuilts/gradle/Interpolator/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/Interpolator/README.md b/prebuilts/gradle/Interpolator/README.md
index 4693e2f..23cdba4 100644
--- a/prebuilts/gradle/Interpolator/README.md
+++ b/prebuilts/gradle/Interpolator/README.md
@@ -23,8 +23,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/JobScheduler/Application/build.gradle b/prebuilts/gradle/JobScheduler/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/JobScheduler/Application/build.gradle
+++ b/prebuilts/gradle/JobScheduler/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/JobScheduler/README.md b/prebuilts/gradle/JobScheduler/README.md
index 2bfdf34..7fb21ed 100644
--- a/prebuilts/gradle/JobScheduler/README.md
+++ b/prebuilts/gradle/JobScheduler/README.md
@@ -8,8 +8,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/JumpingJack/README.md b/prebuilts/gradle/JumpingJack/README.md
index 12cb9c9..090fc4d 100644
--- a/prebuilts/gradle/JumpingJack/README.md
+++ b/prebuilts/gradle/JumpingJack/README.md
@@ -44,8 +44,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/JumpingJack/Wearable/build.gradle b/prebuilts/gradle/JumpingJack/Wearable/build.gradle
index d1db5d1..eafbc95 100644
--- a/prebuilts/gradle/JumpingJack/Wearable/build.gradle
+++ b/prebuilts/gradle/JumpingJack/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/LNotifications/Application/build.gradle b/prebuilts/gradle/LNotifications/Application/build.gradle
index d0481b3..ab2de3b 100644
--- a/prebuilts/gradle/LNotifications/Application/build.gradle
+++ b/prebuilts/gradle/LNotifications/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,8 +34,10 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
diff --git a/prebuilts/gradle/LNotifications/README.md b/prebuilts/gradle/LNotifications/README.md
index 3ea94ca..1c39aaa 100644
--- a/prebuilts/gradle/LNotifications/README.md
+++ b/prebuilts/gradle/LNotifications/README.md
@@ -26,8 +26,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/MediaBrowserService/.google/packaging.yaml b/prebuilts/gradle/MediaBrowserService/.google/packaging.yaml
index d1fd7cb..d1175fc 100644
--- a/prebuilts/gradle/MediaBrowserService/.google/packaging.yaml
+++ b/prebuilts/gradle/MediaBrowserService/.google/packaging.yaml
@@ -17,5 +17,5 @@
     - android:android.support.v4.media.MediaBrowserCompat
     - android:android.support.v4.media.session.MediaSessionCompat
     - android:android.support.v4.media.session.MediaControllerCompat
-    - android:android.support.v7.app.NotificationCompat.MediaStyle
+    - android:android.support.v4.media.app.NotificationCompat.MediaStyle
 license: apache2
diff --git a/prebuilts/gradle/MediaBrowserService/Application/build.gradle b/prebuilts/gradle/MediaBrowserService/Application/build.gradle
index 3b5c585..3621f95 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/build.gradle
+++ b/prebuilts/gradle/MediaBrowserService/Application/build.gradle
@@ -2,25 +2,33 @@
 buildscript {
     repositories {
         jcenter()
+        maven {
+            url 'https://maven.google.com'
+        }
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.1'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
 apply plugin: 'com.android.application'
 
+repositories {
+    jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
+}
 
 dependencies {
 
-    compile "com.android.support:support-v4:25.1.1"
-    compile "com.android.support:support-v13:25.1.1"
-    compile "com.android.support:cardview-v7:25.1.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
 
-    compile 'com.android.support:support-compat:25.3.0'
-    compile 'com.android.support:support-media-compat:25.3.0'
-    compile 'com.android.support:appcompat-v7:25.3.0'
+    compile 'com.android.support:appcompat-v7:26.1.0'
+    compile 'com.android.support.constraint:constraint-layout:1.0.2'
 }
 
 // The sample build uses multiple directories to
@@ -32,14 +40,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 19
-        targetSdkVersion 25
+        targetSdkVersion 26
 
-        vectorDrawables.useSupportLibrary = true
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/MediaBrowserService/Application/proguard-rules.pro b/prebuilts/gradle/MediaBrowserService/Application/proguard-rules.pro
new file mode 100644
index 0000000..a16aac3
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/nazmul/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# 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 *;
+#}
+
+# 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/prebuilts/gradle/MediaBrowserService/Application/src/main/AndroidManifest.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/AndroidManifest.xml
index 570aeb4..6af29f0 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/AndroidManifest.xml
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/AndroidManifest.xml
@@ -1,70 +1,48 @@
-<?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.
+<?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"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="com.example.android.mediabrowserservice"
-    android:versionCode="1"
-    android:versionName="1.0">
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.example.android.mediasession">
+
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
 
     <application
-        android:allowBackup="true"
-        android:icon="@drawable/ic_launcher"
-        android:label="@string/app_name"
-        android:theme="@style/AppTheme"
-        tools:ignore="GoogleAppIndexingWarning,MissingIntentFilterForMediaSearch">
-
-        <meta-data
-            android:name="com.google.android.gms.car.application"
-            android:resource="@xml/automotive_app_desc" />
-
-
-        <activity
-            android:name=".MusicPlayerActivity"
+            android:allowBackup="true"
+            android:icon="@mipmap/ic_launcher"
             android:label="@string/app_name"
-            android:launchMode="singleTop">
+            android:supportsRtl="true"
+            android:theme="@style/AppTheme">
+        <activity
+                android:name=".ui.MainActivity"
+                android:launchMode="singleTop">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
 
-        <!-- (OPTIONAL) use this meta data to indicate which icon should be used in media
-            notifications (for example, when the music changes and the user is
-            looking at another app) -->
-        <meta-data
-            android:name="com.google.android.gms.car.notification.SmallIcon"
-            android:resource="@drawable/ic_notification" />
-
-        <!--
-             (OPTIONAL) use this meta data to override the theme from which Android Auto will
-             look for colors. If you don't set this, Android Auto will look
-             for color attributes in your application theme.
-        -->
-        <meta-data
-            android:name="com.google.android.gms.car.application.theme"
-            android:resource="@style/CarTheme" />
-
         <service
-            android:name=".MusicService"
-            android:exported="true">
+                android:name=".service.MusicService"
+                android:enabled="true"
+                android:exported="true">
             <intent-filter>
-                <action android:name="android.media.browse.MediaBrowserService" />
+                <action android:name="android.media.browse.MediaBrowserService"/>
             </intent-filter>
         </service>
 
@@ -78,10 +56,9 @@
         -->
         <receiver android:name="android.support.v4.media.session.MediaButtonReceiver">
             <intent-filter>
-                <action android:name="android.intent.action.MEDIA_BUTTON" />
+                <action android:name="android.intent.action.MEDIA_BUTTON"/>
             </intent-filter>
         </receiver>
-
     </application>
 
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/assets/jazz_in_paris.mp3 b/prebuilts/gradle/MediaBrowserService/Application/src/main/assets/jazz_in_paris.mp3
new file mode 100644
index 0000000..9a98517
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/assets/jazz_in_paris.mp3
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/assets/the_coldest_shoulder.mp3 b/prebuilts/gradle/MediaBrowserService/Application/src/main/assets/the_coldest_shoulder.mp3
new file mode 100644
index 0000000..5f043d5
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/assets/the_coldest_shoulder.mp3
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/AlbumArtCache.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/AlbumArtCache.java
deleted file mode 100644
index 0f6f13f..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/AlbumArtCache.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.mediabrowserservice;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
-import android.util.Log;
-import android.util.LruCache;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-
-/**
- * Implements a basic cache of album arts, with async loading support.
- */
-public final class AlbumArtCache {
-    private static final String TAG = AlbumArtCache.class.getSimpleName();
-
-    /**
-     * Listener for downloading album art.
-     */
-    public abstract static class FetchListener {
-        public abstract void onFetched(String artUrl, Bitmap bigImage, Bitmap iconImage);
-
-        public void onError(String artUrl, Exception e) {
-            Log.e(TAG, "AlbumArtFetchListener: error while downloading " + artUrl, e);
-        }
-    }
-
-    // Max read limit that we allow our input stream to mark/reset.
-    private static final int MAX_READ_LIMIT_PER_IMG = 1024 * 1024;
-
-    private static final int MAX_ALBUM_ART_CACHE_SIZE = 12 * 1024 * 1024;  // 12 MB
-    private static final int MAX_ART_WIDTH = 800;  // pixels
-    private static final int MAX_ART_HEIGHT = 480;  // pixels
-
-    // Resolution reasonable for carrying around as an icon (generally in
-    // MediaDescription.getIconBitmap). This should not be bigger than necessary, because
-    // the MediaDescription object should be lightweight. If you set it too high and try to
-    // serialize the MediaDescription, you may get FAILED BINDER TRANSACTION errors.
-    private static final int MAX_ART_WIDTH_ICON = 128;  // pixels
-    private static final int MAX_ART_HEIGHT_ICON = 128;  // pixels
-
-    private static final int BIG_BITMAP_INDEX = 0;
-    private static final int ICON_BITMAP_INDEX = 1;
-
-    private final LruCache<String, Bitmap[]> mCache;
-
-    private static final AlbumArtCache sInstance = new AlbumArtCache();
-
-    public static AlbumArtCache getInstance() {
-        return sInstance;
-    }
-
-    private AlbumArtCache() {
-        // Holds no more than MAX_ALBUM_ART_CACHE_SIZE bytes, bounded by maxmemory/4 and
-        // Integer.MAX_VALUE:
-        int maxSize = Math.min(MAX_ALBUM_ART_CACHE_SIZE,
-                (int) (Math.min(Integer.MAX_VALUE, Runtime.getRuntime().maxMemory() / 4)));
-        mCache = new LruCache<String, Bitmap[]>(maxSize) {
-            @Override
-            protected int sizeOf(String key, Bitmap[] value) {
-                return value[BIG_BITMAP_INDEX].getByteCount()
-                        + value[ICON_BITMAP_INDEX].getByteCount();
-            }
-        };
-    }
-
-    public Bitmap getBigImage(String artUrl) {
-        Bitmap[] result = mCache.get(artUrl);
-        return result == null ? null : result[BIG_BITMAP_INDEX];
-    }
-
-    public Bitmap getIconImage(String artUrl) {
-        Bitmap[] result = mCache.get(artUrl);
-        return result == null ? null : result[ICON_BITMAP_INDEX];
-    }
-
-    public void fetch(final String artUrl, final FetchListener listener) {
-        // WARNING: for the sake of simplicity, simultaneous multi-thread fetch requests
-        // are not handled properly: they may cause redundant costly operations, like HTTP
-        // requests and bitmap rescales. For production-level apps, we recommend you use
-        // a proper image loading library, like Glide.
-        Bitmap[] bitmap = mCache.get(artUrl);
-        if (bitmap != null) {
-            Log.d(TAG, "getOrFetch: album art is in cache, using it: " + artUrl);
-            listener.onFetched(artUrl, bitmap[BIG_BITMAP_INDEX], bitmap[ICON_BITMAP_INDEX]);
-            return;
-        }
-        Log.d(TAG, "getOrFetch: starting asynctask to fetch " + artUrl);
-
-        new AsyncTask<Void, Void, Bitmap[]>() {
-            @Override
-            protected Bitmap[] doInBackground(Void[] objects) {
-                Bitmap[] bitmaps;
-                try {
-                    Bitmap bitmap = fetchAndRescaleBitmap(artUrl, MAX_ART_WIDTH, MAX_ART_HEIGHT);
-                    Bitmap icon = scaleBitmap(bitmap, MAX_ART_WIDTH_ICON, MAX_ART_HEIGHT_ICON);
-                    bitmaps = new Bitmap[]{bitmap, icon};
-                    mCache.put(artUrl, bitmaps);
-                } catch (IOException e) {
-                    return null;
-                }
-                Log.d(TAG, "doInBackground: putting bitmap in cache. cache size=" + mCache.size());
-                return bitmaps;
-            }
-
-            @Override
-            protected void onPostExecute(Bitmap[] bitmaps) {
-                if (bitmaps == null) {
-                    listener.onError(artUrl, new IllegalArgumentException("got null bitmaps"));
-                } else {
-                    listener.onFetched(artUrl,
-                            bitmaps[BIG_BITMAP_INDEX], bitmaps[ICON_BITMAP_INDEX]);
-                }
-            }
-        }.execute();
-    }
-
-    private Bitmap scaleBitmap(Bitmap src, int maxWidth, int maxHeight) {
-        double scaleFactor = Math.min(
-                ((double) maxWidth) / src.getWidth(), ((double) maxHeight) / src.getHeight());
-        return Bitmap.createScaledBitmap(src,
-                (int) (src.getWidth() * scaleFactor), (int) (src.getHeight() * scaleFactor), false);
-    }
-
-    private Bitmap scaleBitmap(int scaleFactor, InputStream inputStream) {
-        // Get the dimensions of the bitmap
-        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
-
-        // Decode the image file into a Bitmap sized to fill the View
-        bitmapOptions.inJustDecodeBounds = false;
-        bitmapOptions.inSampleSize = scaleFactor;
-
-        return BitmapFactory.decodeStream(inputStream, null, bitmapOptions);
-    }
-
-    private int findScaleFactor(int targetWidth, int targetHeight, InputStream inputStream) {
-        // Get the dimensions of the bitmap
-        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
-        bitmapOptions.inJustDecodeBounds = true;
-        BitmapFactory.decodeStream(inputStream, null, bitmapOptions);
-        int actualWidth = bitmapOptions.outWidth;
-        int actualHeight = bitmapOptions.outHeight;
-
-        // Determine how much to scale down the image
-        return Math.min(actualWidth / targetWidth, actualHeight / targetHeight);
-    }
-
-    private Bitmap fetchAndRescaleBitmap(String uri, int width, int height)
-            throws IOException {
-        URL url = new URL(uri);
-        BufferedInputStream inputStream = null;
-        try {
-            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
-            inputStream = new BufferedInputStream(urlConnection.getInputStream());
-            inputStream.mark(MAX_READ_LIMIT_PER_IMG);
-            int scaleFactor = findScaleFactor(width, height, inputStream);
-            Log.d(TAG, "Scaling bitmap " + uri + " by factor " + scaleFactor + " to support "
-                    + width + "x" + height + "requested dimension");
-            inputStream.reset();
-            return scaleBitmap(scaleFactor, inputStream);
-        } finally {
-            if (inputStream != null) {
-                inputStream.close();
-            }
-        }
-    }
-}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/BrowseFragment.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/BrowseFragment.java
deleted file mode 100644
index 2e55cd8..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/BrowseFragment.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * 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.mediabrowserservice;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v4.media.MediaBrowserCompat;
-import android.support.v4.media.MediaMetadataCompat;
-import android.support.v4.media.session.MediaControllerCompat;
-import android.support.v4.media.session.PlaybackStateCompat;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A Fragment that lists all the various browsable queues available
- * from a {@link android.service.media.MediaBrowserService}.
- * <p/>
- * It uses a {@link MediaBrowserCompat} to connect to the {@link MusicService}. Once connected,
- * the fragment subscribes to get all the children. All {@link MediaBrowserCompat.MediaItem}'s
- * that can be browsed are shown in a ListView.
- */
-public class BrowseFragment extends Fragment {
-
-    private static final String TAG = BrowseFragment.class.getSimpleName();
-
-    public static final String ARG_MEDIA_ID = "media_id";
-
-    /**
-     * Interface between BrowseFragment and MusicPlayerActivity.
-     */
-    public interface FragmentDataHelper {
-        void onMediaItemSelected(MediaBrowserCompat.MediaItem item, boolean isPlaying);
-    }
-
-    // The mediaId to be used for subscribing for children using the MediaBrowser.
-    private String mMediaId;
-
-    private MediaBrowserCompat mMediaBrowser;
-    private BrowseAdapter mBrowserAdapter;
-
-    private MediaBrowserCompat.SubscriptionCallback mSubscriptionCallback =
-            new MediaBrowserCompat.SubscriptionCallback() {
-
-                @Override
-                public void onChildrenLoaded(String parentId,
-                                             List<MediaBrowserCompat.MediaItem> children) {
-                    mBrowserAdapter.clear();
-                    mBrowserAdapter.notifyDataSetInvalidated();
-                    for (MediaBrowserCompat.MediaItem item : children) {
-                        mBrowserAdapter.add(item);
-                    }
-                    mBrowserAdapter.notifyDataSetChanged();
-                }
-
-                @Override
-                public void onError(String id) {
-                    Toast.makeText(getActivity(), R.string.error_loading_media,
-                            Toast.LENGTH_LONG).show();
-                }
-            };
-
-    private MediaBrowserCompat.ConnectionCallback mConnectionCallback =
-            new MediaBrowserCompat.ConnectionCallback() {
-                @Override
-                public void onConnected() {
-                    Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken());
-
-                    if (mMediaId == null) {
-                        mMediaId = mMediaBrowser.getRoot();
-                    }
-                    mMediaBrowser.subscribe(mMediaId, mSubscriptionCallback);
-                    try {
-                        MediaControllerCompat mediaController =
-                                new MediaControllerCompat(getActivity(),
-                                        mMediaBrowser.getSessionToken());
-                        MediaControllerCompat.setMediaController(getActivity(), mediaController);
-
-                        // Register a Callback to stay in sync
-                        mediaController.registerCallback(mControllerCallback);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Failed to connect to MediaController", e);
-                    }
-                }
-
-                @Override
-                public void onConnectionFailed() {
-                    Log.e(TAG, "onConnectionFailed");
-                }
-
-                @Override
-                public void onConnectionSuspended() {
-                    Log.d(TAG, "onConnectionSuspended");
-                    MediaControllerCompat mediaController = MediaControllerCompat
-                            .getMediaController(getActivity());
-                    if (mediaController != null) {
-                        mediaController.unregisterCallback(mControllerCallback);
-                        MediaControllerCompat.setMediaController(getActivity(), null);
-                    }
-                }
-            };
-
-    private MediaControllerCompat.Callback mControllerCallback =
-            new MediaControllerCompat.Callback() {
-                @Override
-                public void onMetadataChanged(MediaMetadataCompat metadata) {
-                    if (metadata != null) {
-                        mBrowserAdapter.setCurrentMediaMetadata(metadata);
-                    }
-                }
-
-                @Override
-                public void onPlaybackStateChanged(PlaybackStateCompat state) {
-                    mBrowserAdapter.setPlaybackState(state);
-                    mBrowserAdapter.notifyDataSetChanged();
-                }
-            };
-
-    public static BrowseFragment newInstance(String mediaId) {
-        Bundle args = new Bundle();
-        args.putString(ARG_MEDIA_ID, mediaId);
-        BrowseFragment fragment = new BrowseFragment();
-        fragment.setArguments(args);
-        return fragment;
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-                             Bundle savedInstanceState) {
-        View rootView = inflater.inflate(R.layout.fragment_list, container, false);
-
-        mBrowserAdapter = new BrowseAdapter(getActivity());
-
-        ListView listView = (ListView) rootView.findViewById(R.id.list_view);
-        listView.setAdapter(mBrowserAdapter);
-        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-            @Override
-            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                MediaBrowserCompat.MediaItem item = mBrowserAdapter.getItem(position);
-                boolean isPlaying = item.getMediaId().equals(mBrowserAdapter.getPlayingMediaId());
-                try {
-                    FragmentDataHelper listener = (FragmentDataHelper) getActivity();
-                    listener.onMediaItemSelected(item, isPlaying);
-                } catch (ClassCastException ex) {
-                    Log.e(TAG, "Exception trying to cast to FragmentDataHelper", ex);
-                }
-            }
-        });
-
-        Bundle args = getArguments();
-        mMediaId = args.getString(ARG_MEDIA_ID, null);
-
-        mMediaBrowser = new MediaBrowserCompat(getActivity(),
-                new ComponentName(getActivity(), MusicService.class),
-                mConnectionCallback, null);
-
-        return rootView;
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        mMediaBrowser.connect();
-    }
-
-    @Override
-    public void onStop() {
-        super.onStop();
-        mMediaBrowser.disconnect();
-    }
-
-    // An adapter for showing the list of browsed MediaItem's
-    private static class BrowseAdapter extends ArrayAdapter<MediaBrowserCompat.MediaItem> {
-        private String mCurrentMediaId;
-        private PlaybackStateCompat mPlaybackState;
-
-        public BrowseAdapter(Context context) {
-            super(context, R.layout.media_list_item, new ArrayList<MediaBrowserCompat.MediaItem>());
-        }
-
-        @Nullable
-        public String getPlayingMediaId() {
-            boolean isPlaying = mPlaybackState != null
-                    && mPlaybackState.getState() == PlaybackStateCompat.STATE_PLAYING;
-            return isPlaying ? mCurrentMediaId : null;
-        }
-
-        private void setCurrentMediaMetadata(MediaMetadataCompat mediaMetadata) {
-            mCurrentMediaId = mediaMetadata != null
-                    ? mediaMetadata.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID)
-                    : null;
-        }
-
-        private void setPlaybackState(PlaybackStateCompat playbackState) {
-            mPlaybackState = playbackState;
-        }
-
-        static class ViewHolder {
-            ImageView mImageView;
-            TextView mTitleView;
-            TextView mDescriptionView;
-        }
-
-        @NonNull
-        @Override
-        public View getView(int position, View convertView, @NonNull ViewGroup parent) {
-
-            ViewHolder holder;
-
-            if (convertView == null) {
-                convertView = LayoutInflater.from(getContext())
-                        .inflate(R.layout.media_list_item, parent, false);
-                holder = new ViewHolder();
-                holder.mImageView = (ImageView) convertView.findViewById(R.id.play_eq);
-                holder.mImageView.setVisibility(View.GONE);
-                holder.mTitleView = (TextView) convertView.findViewById(R.id.title);
-                holder.mDescriptionView = (TextView) convertView.findViewById(R.id.description);
-                convertView.setTag(holder);
-            } else {
-                holder = (ViewHolder) convertView.getTag();
-            }
-
-            MediaBrowserCompat.MediaItem item = getItem(position);
-            holder.mTitleView.setText(item.getDescription().getTitle());
-            holder.mDescriptionView.setText(item.getDescription().getDescription());
-            if (item.isPlayable()) {
-                int playRes = item.getMediaId().equals(getPlayingMediaId())
-                        ? R.drawable.ic_equalizer_white_24dp
-                        : R.drawable.ic_play_arrow_white_24dp;
-                holder.mImageView.setImageDrawable(getContext().getResources()
-                        .getDrawable(playRes));
-                holder.mImageView.setVisibility(View.VISIBLE);
-            }
-            return convertView;
-        }
-
-    }
-}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotificationHelper.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotificationHelper.java
deleted file mode 100644
index 4cda405..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotificationHelper.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.mediabrowserservice;
-
-import android.app.Notification;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.support.v4.media.MediaDescriptionCompat;
-import android.support.v4.media.MediaMetadataCompat;
-import android.support.v4.media.session.MediaButtonReceiver;
-import android.support.v4.media.session.MediaControllerCompat;
-import android.support.v4.media.session.MediaSessionCompat;
-import android.support.v4.media.session.PlaybackStateCompat;
-import android.support.v7.app.NotificationCompat;
-
-/**
- * Helper class for building Media style Notifications from a
- * {@link android.support.v4.media.session.MediaSessionCompat}.
- */
-public class MediaNotificationHelper {
-    private MediaNotificationHelper() {
-        // Helper utility class; do not instantiate.
-    }
-
-    public static Notification createNotification(Context context,
-                                                  MediaSessionCompat mediaSession) {
-        MediaControllerCompat controller = mediaSession.getController();
-        MediaMetadataCompat mMetadata = controller.getMetadata();
-        PlaybackStateCompat mPlaybackState = controller.getPlaybackState();
-
-        if (mMetadata == null || mPlaybackState == null) {
-            return null;
-        }
-
-        boolean isPlaying = mPlaybackState.getState() == PlaybackStateCompat.STATE_PLAYING;
-        NotificationCompat.Action action = isPlaying
-                ? new NotificationCompat.Action(R.drawable.ic_pause_white_24dp,
-                    context.getString(R.string.label_pause),
-                    MediaButtonReceiver.buildMediaButtonPendingIntent(context,
-                            PlaybackStateCompat.ACTION_PAUSE))
-                : new NotificationCompat.Action(R.drawable.ic_play_arrow_white_24dp,
-                    context.getString(R.string.label_play),
-                    MediaButtonReceiver.buildMediaButtonPendingIntent(context,
-                            PlaybackStateCompat.ACTION_PLAY));
-
-        MediaDescriptionCompat description = mMetadata.getDescription();
-        Bitmap art = description.getIconBitmap();
-        if (art == null) {
-            // use a placeholder art while the remote art is being downloaded.
-            art = BitmapFactory.decodeResource(context.getResources(),
-                    R.drawable.ic_default_art);
-        }
-
-        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context);
-        notificationBuilder
-                .setStyle(new NotificationCompat.MediaStyle()
-                        // show only play/pause in compact view.
-                        .setShowActionsInCompactView(new int[]{0})
-                        .setMediaSession(mediaSession.getSessionToken()))
-                .addAction(action)
-                .setSmallIcon(R.drawable.ic_notification)
-                .setShowWhen(false)
-                .setContentIntent(controller.getSessionActivity())
-                .setContentTitle(description.getTitle())
-                .setContentText(description.getSubtitle())
-                .setLargeIcon(art)
-                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
-
-        return notificationBuilder.build();
-    }
-}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicPlayerActivity.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicPlayerActivity.java
deleted file mode 100644
index 0a3a7df..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicPlayerActivity.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.mediabrowserservice;
-
-import android.os.Bundle;
-import android.support.v4.media.MediaBrowserCompat;
-import android.support.v4.media.session.MediaControllerCompat;
-import android.support.v7.app.AppCompatActivity;
-
-/**
- * Main activity for the music player.
- */
-public class MusicPlayerActivity extends AppCompatActivity
-        implements BrowseFragment.FragmentDataHelper {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.activity_player);
-        if (savedInstanceState == null) {
-            getSupportFragmentManager().beginTransaction()
-                    .add(R.id.container, BrowseFragment.newInstance(null))
-                    .commit();
-        }
-    }
-
-    @Override
-    public void onMediaItemSelected(MediaBrowserCompat.MediaItem item, boolean isPlaying) {
-        if (item.isPlayable()) {
-            MediaControllerCompat controller = MediaControllerCompat.getMediaController(this);
-            MediaControllerCompat.TransportControls controls = controller.getTransportControls();
-
-            // If the item is playing, pause it, otherwise start it
-            if (isPlaying) {
-                controls.pause();
-            } else {
-                controls.playFromMediaId(item.getMediaId(), null);
-            }
-        } else if (item.isBrowsable()) {
-            getSupportFragmentManager().beginTransaction()
-                    .replace(R.id.container, BrowseFragment.newInstance(item.getMediaId()))
-                    .addToBackStack(null)
-                    .commit();
-        }
-    }
-}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicService.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicService.java
deleted file mode 100644
index 1cfb023..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicService.java
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
-* 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.mediabrowserservice;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Bitmap;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.support.annotation.NonNull;
-import android.support.v4.app.NotificationManagerCompat;
-import android.support.v4.media.MediaBrowserCompat;
-import android.support.v4.media.MediaBrowserServiceCompat;
-import android.support.v4.media.MediaMetadataCompat;
-import android.support.v4.media.session.MediaButtonReceiver;
-import android.support.v4.media.session.MediaSessionCompat;
-import android.support.v4.media.session.PlaybackStateCompat;
-import android.util.Log;
-
-import com.example.android.mediabrowserservice.model.MusicProvider;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import static com.example.android.mediabrowserservice.model.MusicProvider.MEDIA_ID_EMPTY_ROOT;
-import static com.example.android.mediabrowserservice.model.MusicProvider.MEDIA_ID_ROOT;
-
-/**
- * This class provides a MediaBrowser through a service. It exposes the media library to a browsing
- * client, through the onGetRoot and onLoadChildren methods. It also creates a MediaSession and
- * exposes it through its MediaSession.Token, which allows the client to create a MediaController
- * that connects to and send control commands to the MediaSession remotely. This is useful for
- * user interfaces that need to interact with your media session, like Android Auto. You can
- * (should) also use the same service from your app's UI, which gives a seamless playback
- * experience to the user.
- * <p>
- * To implement a MediaBrowserService, you need to:
- * <p>
- * <ul>
- * <p>
- * <li> Extend {@link android.support.v4.media.MediaBrowserServiceCompat}, implementing the media
- * browsing related methods {@link android.support.v4.media.MediaBrowserServiceCompat#onGetRoot} and
- * {@link android.support.v4.media.MediaBrowserServiceCompat#onLoadChildren};
- * <li> In onCreate, start a new {@link android.support.v4.media.session.MediaSessionCompat} and
- * notify its parent with the session's token
- * {@link android.support.v4.media.MediaBrowserServiceCompat#setSessionToken};
- * <p>
- * <li> Set a callback on the
- * {@link android.support.v4.media.session.MediaSessionCompat#setCallback(MediaSessionCompat.Callback)}.
- * The callback will receive all the user's actions, like play, pause, etc;
- * <p>
- * <li> Handle all the actual music playing using any method your app prefers (for example,
- * {@link android.media.MediaPlayer})
- * <p>
- * <li> Update playbackState, "now playing" metadata and queue, using MediaSession proper methods
- * {@link android.support.v4.media.session.MediaSessionCompat#setPlaybackState(PlaybackStateCompat)}
- * {@link android.support.v4.media.session.MediaSessionCompat#setMetadata(MediaMetadataCompat)} and
- * if your implementation allows it,
- * {@link android.support.v4.media.session.MediaSessionCompat#setQueue(List)})
- * <p>
- * <li> Declare and export the service in AndroidManifest with an intent receiver for the action
- * android.media.browse.MediaBrowserService
- * <li> Declare a broadcast receiver to receive media button events. This is required if your app
- * supports Android KitKat or previous:
- * &lt;receiver android:name="android.support.v4.media.session.MediaButtonReceiver"&gt;
- * &lt;intent-filter&gt;
- * &lt;action android:name="android.intent.action.MEDIA_BUTTON" /&gt;
- * &lt;/intent-filter&gt;
- * &lt;/receiver&gt;
- * <p>
- * </ul>
- * <p>
- * To make your app compatible with Android Auto, you also need to:
- * <p>
- * <ul>
- * <p>
- * <li> Declare a meta-data tag in AndroidManifest.xml linking to a xml resource
- * with a &lt;automotiveApp&gt; root element. For a media app, this must include
- * an &lt;uses name="media"/&gt; element as a child.
- * For example, in AndroidManifest.xml:
- * &lt;meta-data android:name="com.google.android.gms.car.application"
- * android:resource="@xml/automotive_app_desc"/&gt;
- * And in res/values/automotive_app_desc.xml:
- * &lt;automotiveApp&gt;
- * &lt;uses name="media"/&gt;
- * &lt;/automotiveApp&gt;
- * <p>
- * </ul>
- *
- * @see <a href="README.md">README.md</a> for more details.
- */
-
-public class MusicService extends MediaBrowserServiceCompat {
-    private static final String TAG = MusicService.class.getSimpleName();
-
-    // ID for our MediaNotification.
-    public static final int NOTIFICATION_ID = 412;
-
-    // Request code for starting the UI.
-    private static final int REQUEST_CODE = 99;
-
-    // Delay stopSelf by using a handler.
-    private static final long STOP_DELAY = TimeUnit.SECONDS.toMillis(30);
-    private static final int STOP_CMD = 0x7c48;
-
-    private MusicProvider mMusicProvider;
-    private MediaSessionCompat mSession;
-    public NotificationManagerCompat mNotificationManager;
-    // Indicates whether the service was started.
-    private boolean mServiceStarted;
-    private Playback mPlayback;
-    private MediaSessionCompat.QueueItem mCurrentMedia;
-    private AudioBecomingNoisyReceiver mAudioBecomingNoisyReceiver;
-
-    /**
-     * Custom {@link Handler} to process the delayed stop command.
-     */
-    private Handler mDelayedStopHandler = new Handler(new Handler.Callback() {
-        @Override
-        public boolean handleMessage(Message msg) {
-            if (msg == null || msg.what != STOP_CMD) {
-                return false;
-            }
-
-            if (!mPlayback.isPlaying()) {
-                Log.d(TAG, "Stopping service");
-                stopSelf();
-                mServiceStarted = false;
-            }
-            return false;
-        }
-    });
-
-    /*
-     * (non-Javadoc)
-     * @see android.app.Service#onCreate()
-     */
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        Log.d(TAG, "onCreate");
-
-        mMusicProvider = new MusicProvider();
-
-        // Start a new MediaSession.
-        mSession = new MediaSessionCompat(this, TAG);
-        setSessionToken(mSession.getSessionToken());
-        mSession.setCallback(new MediaSessionCallback());
-        mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
-                | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
-
-        mPlayback = new Playback(this, mMusicProvider);
-        mPlayback.setCallback(new Playback.Callback() {
-            @Override
-            public void onPlaybackStatusChanged(int state) {
-                updatePlaybackState(null);
-            }
-
-            @Override
-            public void onCompletion() {
-                // In this simple implementation there isn't a play queue, so we simply 'stop' after
-                // the song is over.
-                handleStopRequest();
-            }
-
-            @Override
-            public void onError(String error) {
-                updatePlaybackState(error);
-            }
-        });
-
-        Context context = getApplicationContext();
-
-        // This is an Intent to launch the app's UI, used primarily by the ongoing notification.
-        Intent intent = new Intent(context, MusicPlayerActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        PendingIntent pi = PendingIntent.getActivity(context, REQUEST_CODE, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
-        mSession.setSessionActivity(pi);
-
-        mNotificationManager = NotificationManagerCompat.from(this);
-        mAudioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(this);
-
-        updatePlaybackState(null);
-    }
-
-    /**
-     * (non-Javadoc)
-     *
-     * @see android.app.Service#onStartCommand(android.content.Intent, int, int)
-     */
-    @Override
-    public int onStartCommand(Intent startIntent, int flags, int startId) {
-        MediaButtonReceiver.handleIntent(mSession, startIntent);
-        return super.onStartCommand(startIntent, flags, startId);
-    }
-
-    /**
-     * (non-Javadoc)
-     *
-     * @see android.app.Service#onDestroy()
-     */
-    @Override
-    public void onDestroy() {
-        Log.d(TAG, "onDestroy");
-        // Service is being killed, so make sure we release our resources
-        handleStopRequest();
-
-        mDelayedStopHandler.removeCallbacksAndMessages(null);
-        // Always release the MediaSession to clean up resources
-        // and notify associated MediaController(s).
-        mSession.release();
-    }
-
-    @Override
-    public BrowserRoot onGetRoot(@NonNull String clientPackageName,
-                                 int clientUid, Bundle rootHints) {
-        // Verify the client is authorized to browse media and return the root that
-        // makes the most sense here. In this example we simply verify the package name
-        // is the same as ours, but more complicated checks, and responses, are possible
-        if (!clientPackageName.equals(getPackageName())) {
-            // Allow the client to connect, but not browse, by returning an empty root
-            return new BrowserRoot(MEDIA_ID_EMPTY_ROOT, null);
-        }
-        return new BrowserRoot(MEDIA_ID_ROOT, null);
-    }
-
-    @Override
-    public void onLoadChildren(@NonNull final String parentMediaId,
-                               @NonNull final Result<List<MediaBrowserCompat.MediaItem>> result) {
-        Log.d(TAG, "OnLoadChildren: parentMediaId=" + parentMediaId);
-
-        if (!mMusicProvider.isInitialized()) {
-            // Use result.detach to allow calling result.sendResult from another thread:
-            result.detach();
-
-            mMusicProvider.retrieveMediaAsync(new MusicProvider.Callback() {
-                @Override
-                public void onMusicCatalogReady(boolean success) {
-                    if (success) {
-                        loadChildrenImpl(parentMediaId, result);
-                    } else {
-                        updatePlaybackState(getString(R.string.error_no_metadata));
-                        result.sendResult(Collections.<MediaBrowserCompat.MediaItem>emptyList());
-                    }
-                }
-            });
-
-        } else {
-            // If our music catalog is already loaded/cached, load them into result immediately
-            loadChildrenImpl(parentMediaId, result);
-        }
-    }
-
-    /**
-     * Actual implementation of onLoadChildren that assumes that MusicProvider is already
-     * initialized.
-     */
-    private void loadChildrenImpl(@NonNull final String parentMediaId,
-                                  final Result<List<MediaBrowserCompat.MediaItem>> result) {
-        List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
-
-        switch (parentMediaId) {
-            case MEDIA_ID_ROOT:
-                for (MediaMetadataCompat track : mMusicProvider.getAllMusics()) {
-                    MediaBrowserCompat.MediaItem bItem =
-                            new MediaBrowserCompat.MediaItem(track.getDescription(),
-                                    MediaBrowserCompat.MediaItem.FLAG_PLAYABLE);
-                    mediaItems.add(bItem);
-                }
-                break;
-            case MEDIA_ID_EMPTY_ROOT:
-                // Since the client provided the empty root we'll just send back an
-                // empty list
-                break;
-            default:
-                Log.w(TAG, "Skipping unmatched parentMediaId: " + parentMediaId);
-                break;
-        }
-        result.sendResult(mediaItems);
-    }
-
-    private final class MediaSessionCallback extends MediaSessionCompat.Callback {
-
-        @Override
-        public void onPlayFromMediaId(String mediaId, Bundle extras) {
-            Log.d(TAG, "playFromMediaId mediaId:" + mediaId + "  extras=" + extras);
-
-            // The mediaId used here is not the unique musicId. This one comes from the
-            // MediaBrowser, and is actually a "hierarchy-aware mediaID": a concatenation of
-            // the hierarchy in MediaBrowser and the actual unique musicID. This is necessary
-            // so we can build the correct playing queue, based on where the track was
-            // selected from.
-            MediaMetadataCompat media = mMusicProvider.getMusic(mediaId);
-            if (media != null) {
-                mCurrentMedia =
-                        new MediaSessionCompat.QueueItem(media.getDescription(), media.hashCode());
-
-                // play the music
-                handlePlayRequest();
-            }
-        }
-
-        @Override
-        public void onPlay() {
-            Log.d(TAG, "play");
-
-            if (mCurrentMedia != null) {
-                handlePlayRequest();
-            }
-        }
-
-        @Override
-        public void onSeekTo(long position) {
-            Log.d(TAG, "onSeekTo:" + position);
-            mPlayback.seekTo((int) position);
-        }
-
-        @Override
-        public void onPause() {
-            Log.d(TAG, "pause. current state=" + mPlayback.getState());
-            handlePauseRequest();
-        }
-
-        @Override
-        public void onStop() {
-            Log.d(TAG, "stop. current state=" + mPlayback.getState());
-            handleStopRequest();
-        }
-    }
-
-    /**
-     * Handle a request to play music
-     */
-    private void handlePlayRequest() {
-        Log.d(TAG, "handlePlayRequest: mState=" + mPlayback.getState());
-
-        if (mCurrentMedia == null) {
-            // Nothing to play
-            return;
-        }
-
-        mDelayedStopHandler.removeCallbacksAndMessages(null);
-        if (!mServiceStarted) {
-            Log.v(TAG, "Starting service");
-            // The MusicService needs to keep running even after the calling MediaBrowser
-            // is disconnected. Call startService(Intent) and then stopSelf(..) when we no longer
-            // need to play media.
-            startService(new Intent(getApplicationContext(), MusicService.class));
-            mServiceStarted = true;
-        }
-
-        if (!mSession.isActive()) {
-            mSession.setActive(true);
-        }
-
-        updateMetadata();
-        mPlayback.play(mCurrentMedia);
-    }
-
-    /**
-     * Handle a request to pause music
-     */
-    private void handlePauseRequest() {
-        Log.d(TAG, "handlePauseRequest: mState=" + mPlayback.getState());
-        mPlayback.pause();
-
-        // reset the delayed stop handler.
-        mDelayedStopHandler.removeCallbacksAndMessages(null);
-        mDelayedStopHandler.sendEmptyMessageDelayed(STOP_CMD, STOP_DELAY);
-    }
-
-    /**
-     * Handle a request to stop music
-     */
-    private void handleStopRequest() {
-        Log.d(TAG, "handleStopRequest: mState=" + mPlayback.getState());
-        mPlayback.stop();
-        // reset the delayed stop handler.
-        mDelayedStopHandler.removeCallbacksAndMessages(null);
-        mDelayedStopHandler.sendEmptyMessage(STOP_CMD);
-
-        updatePlaybackState(null);
-    }
-
-    private void updateMetadata() {
-        MediaSessionCompat.QueueItem queueItem = mCurrentMedia;
-        String musicId = queueItem.getDescription().getMediaId();
-        MediaMetadataCompat track = mMusicProvider.getMusic(musicId);
-
-        final String trackId = track.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID);
-        mSession.setMetadata(track);
-
-        // Set the proper album artwork on the media session, so it can be shown in the
-        // locked screen and in other places.
-        if (track.getDescription().getIconBitmap() == null
-                && track.getDescription().getIconUri() != null) {
-            fetchArtwork(trackId, track.getDescription().getIconUri());
-            postNotification();
-        }
-    }
-
-    private void fetchArtwork(final String trackId, final Uri albumUri) {
-        AlbumArtCache.getInstance().fetch(albumUri.toString(),
-                new AlbumArtCache.FetchListener() {
-                    @Override
-                    public void onFetched(String artUrl, Bitmap bitmap, Bitmap icon) {
-                        MediaSessionCompat.QueueItem queueItem = mCurrentMedia;
-                        MediaMetadataCompat track = mMusicProvider.getMusic(trackId);
-                        track = new MediaMetadataCompat.Builder(track)
-
-                                // Set high resolution bitmap in METADATA_KEY_ALBUM_ART. This is
-                                // used, for example, on the lockscreen background when the media
-                                // session is active.
-                                .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
-
-                                // Set small version of the album art in the DISPLAY_ICON. This is
-                                // used on the MediaDescription and thus it should be small to be
-                                // serialized if necessary.
-                                .putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, icon)
-
-                                .build();
-
-                        mMusicProvider.updateMusic(trackId, track);
-
-                        // If we are still playing the same music
-                        String currentPlayingId = queueItem.getDescription().getMediaId();
-                        if (trackId.equals(currentPlayingId)) {
-                            mSession.setMetadata(track);
-                            postNotification();
-                        }
-                    }
-                });
-    }
-
-    /**
-     * Update the current media player state, optionally showing an error message.
-     *
-     * @param error if not null, error message to present to the user.
-     */
-    private void updatePlaybackState(String error) {
-        Log.d(TAG, "updatePlaybackState, playback state=" + mPlayback.getState());
-        long position = PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN;
-        if (mPlayback != null && mPlayback.isConnected()) {
-            position = mPlayback.getCurrentStreamPosition();
-        }
-
-        long playbackActions = PlaybackStateCompat.ACTION_PLAY
-                | PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID;
-        if (mPlayback.isPlaying()) {
-            playbackActions |= PlaybackStateCompat.ACTION_PAUSE;
-        }
-
-        PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder()
-                .setActions(playbackActions);
-
-        int state = mPlayback.getState();
-
-        // If there is an error message, send it to the playback state:
-        if (error != null) {
-            // Error states are really only supposed to be used for errors that cause playback to
-            // stop unexpectedly and persist until the user takes action to fix it.
-            stateBuilder.setErrorMessage(error);
-            state = PlaybackStateCompat.STATE_ERROR;
-        }
-
-        // Because the playback state is pulled from the Playback class lint thinks it may not
-        // match permitted values.
-        //noinspection WrongConstant
-        stateBuilder.setState(state, position, 1.0f, SystemClock.elapsedRealtime());
-
-        // Set the activeQueueItemId if the current index is valid.
-        if (mCurrentMedia != null) {
-            stateBuilder.setActiveQueueItemId(mCurrentMedia.getQueueId());
-        }
-
-        mSession.setPlaybackState(stateBuilder.build());
-
-        if (state == PlaybackStateCompat.STATE_PLAYING) {
-            Notification notification = postNotification();
-            startForeground(NOTIFICATION_ID, notification);
-            mAudioBecomingNoisyReceiver.register();
-        } else {
-            if (state == PlaybackStateCompat.STATE_PAUSED) {
-                postNotification();
-            } else {
-                mNotificationManager.cancel(NOTIFICATION_ID);
-            }
-            stopForeground(false);
-            mAudioBecomingNoisyReceiver.unregister();
-        }
-    }
-
-    private Notification postNotification() {
-        Notification notification = MediaNotificationHelper.createNotification(this, mSession);
-        if (notification == null) {
-            return null;
-        }
-
-        mNotificationManager.notify(NOTIFICATION_ID, notification);
-        return notification;
-    }
-
-    /**
-     * Implementation of the AudioManager.ACTION_AUDIO_BECOMING_NOISY Receiver.
-     */
-
-    private class AudioBecomingNoisyReceiver extends BroadcastReceiver {
-        private final Context mContext;
-        private boolean mIsRegistered = false;
-
-        private IntentFilter mAudioNoisyIntentFilter =
-                new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
-
-        protected AudioBecomingNoisyReceiver(Context context) {
-            mContext = context.getApplicationContext();
-        }
-
-        public void register() {
-            if (!mIsRegistered) {
-                mContext.registerReceiver(this, mAudioNoisyIntentFilter);
-                mIsRegistered = true;
-            }
-        }
-
-        public void unregister() {
-            if (mIsRegistered) {
-                mContext.unregisterReceiver(this);
-                mIsRegistered = false;
-            }
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
-                handlePauseRequest();
-            }
-        }
-    }
-}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/Playback.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/Playback.java
deleted file mode 100644
index 6af2d41..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/Playback.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * 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.mediabrowserservice;
-
-import android.content.Context;
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-import android.net.wifi.WifiManager;
-import android.os.PowerManager;
-import android.support.v4.media.MediaMetadataCompat;
-import android.support.v4.media.session.MediaSessionCompat;
-import android.support.v4.media.session.PlaybackStateCompat;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.example.android.mediabrowserservice.model.MusicProvider;
-
-import java.io.IOException;
-
-import static android.media.MediaPlayer.OnCompletionListener;
-import static android.media.MediaPlayer.OnErrorListener;
-import static android.media.MediaPlayer.OnPreparedListener;
-import static android.media.MediaPlayer.OnSeekCompleteListener;
-
-/**
- * A class that implements local media playback using {@link android.media.MediaPlayer}
- */
-public class Playback implements AudioManager.OnAudioFocusChangeListener,
-        OnCompletionListener, OnErrorListener, OnPreparedListener, OnSeekCompleteListener {
-
-    private static final String TAG = Playback.class.getSimpleName();
-
-    /* package */ interface Callback {
-        /**
-         * On current music completed.
-         */
-        void onCompletion();
-
-        /**
-         * on Playback status changed
-         * Implementations can use this callback to update
-         * playback state on the media sessions.
-         */
-        void onPlaybackStatusChanged(int state);
-
-        /**
-         * @param error to be added to the PlaybackState
-         */
-        void onError(String error);
-
-    }
-
-    // The volume we set the media player to when we lose audio focus, but are
-    // allowed to reduce the volume instead of stopping playback.
-    public static final float VOLUME_DUCK = 0.2f;
-    // The volume we set the media player when we have audio focus.
-    public static final float VOLUME_NORMAL = 1.0f;
-
-    // we don't have audio focus, and can't duck (play at a low volume)
-    private static final int AUDIO_NO_FOCUS_NO_DUCK = 0;
-    // we don't have focus, but can duck (play at a low volume)
-    private static final int AUDIO_NO_FOCUS_CAN_DUCK = 1;
-    // we have full audio focus
-    private static final int AUDIO_FOCUSED = 2;
-
-    private final MusicService mService;
-    private final MusicProvider mMusicProvider;
-    private final WifiManager.WifiLock mWifiLock;
-    private int mState = PlaybackStateCompat.STATE_NONE;
-    private boolean mPlayOnFocusGain;
-    private Callback mCallback;
-    private volatile int mCurrentPosition;
-    private volatile String mCurrentMediaId;
-
-    // Type of audio focus we have:
-    private int mAudioFocus = AUDIO_NO_FOCUS_NO_DUCK;
-    private AudioManager mAudioManager;
-    private MediaPlayer mMediaPlayer;
-
-    public Playback(MusicService service, MusicProvider musicProvider) {
-        Context context = service.getApplicationContext();
-        this.mService = service;
-        this.mMusicProvider = musicProvider;
-        this.mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-
-        // Create the Wifi lock (this does not acquire the lock, this just creates it).
-        this.mWifiLock = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE))
-                .createWifiLock(WifiManager.WIFI_MODE_FULL, "sample_lock");
-    }
-
-    public void stop() {
-        mState = PlaybackStateCompat.STATE_STOPPED;
-        if (mCallback != null) {
-            mCallback.onPlaybackStatusChanged(mState);
-        }
-        mCurrentPosition = getCurrentStreamPosition();
-        // Give up Audio focus
-        giveUpAudioFocus();
-        // Relax all resources
-        relaxResources(true);
-        if (mWifiLock.isHeld()) {
-            mWifiLock.release();
-        }
-    }
-
-    public int getState() {
-        return mState;
-    }
-
-    public boolean isConnected() {
-        return true;
-    }
-
-    public boolean isPlaying() {
-        return mPlayOnFocusGain || (mMediaPlayer != null && mMediaPlayer.isPlaying());
-    }
-
-    public int getCurrentStreamPosition() {
-        return mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : mCurrentPosition;
-    }
-
-    public void play(MediaSessionCompat.QueueItem item) {
-        mPlayOnFocusGain = true;
-        tryToGetAudioFocus();
-        String mediaId = item.getDescription().getMediaId();
-        boolean mediaHasChanged = !TextUtils.equals(mediaId, mCurrentMediaId);
-        if (mediaHasChanged) {
-            mCurrentPosition = 0;
-            mCurrentMediaId = mediaId;
-        }
-
-        if (mState == PlaybackStateCompat.STATE_PAUSED
-                && !mediaHasChanged && mMediaPlayer != null) {
-            configMediaPlayerState();
-        } else {
-            mState = PlaybackStateCompat.STATE_STOPPED;
-            relaxResources(false); // release everything except MediaPlayer
-            MediaMetadataCompat track = mMusicProvider.getMusic(item.getDescription().getMediaId());
-
-            String source = track.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI);
-            try {
-                createMediaPlayerIfNeeded();
-
-                mState = PlaybackStateCompat.STATE_BUFFERING;
-
-                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
-                mMediaPlayer.setDataSource(source);
-
-                // Starts preparing the media player in the background. When
-                // it's done, it will call our OnPreparedListener (that is,
-                // the onPrepared() method on this class, since we set the
-                // listener to 'this'). Until the media player is prepared,
-                // we *cannot* call start() on it!
-                mMediaPlayer.prepareAsync();
-
-                // If we are streaming from the internet, we want to hold a
-                // Wifi lock, which prevents the Wifi radio from going to
-                // sleep while the song is playing.
-                mWifiLock.acquire();
-
-                if (mCallback != null) {
-                    mCallback.onPlaybackStatusChanged(mState);
-                }
-
-            } catch (IOException ioException) {
-                Log.e(TAG, "Exception playing song", ioException);
-                if (mCallback != null) {
-                    mCallback.onError(ioException.getMessage());
-                }
-            }
-        }
-    }
-
-    public void pause() {
-        if (mState == PlaybackStateCompat.STATE_PLAYING) {
-            // Pause media player and cancel the 'foreground service' state.
-            if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
-                mMediaPlayer.pause();
-                mCurrentPosition = mMediaPlayer.getCurrentPosition();
-            }
-            // while paused, retain the MediaPlayer but give up audio focus
-            relaxResources(false);
-        }
-        mState = PlaybackStateCompat.STATE_PAUSED;
-        if (mCallback != null) {
-            mCallback.onPlaybackStatusChanged(mState);
-        }
-    }
-
-    public void seekTo(int position) {
-        Log.d(TAG, "seekTo called with " + position);
-
-        if (mMediaPlayer == null) {
-            // If we do not have a current media player, simply update the current position.
-            mCurrentPosition = position;
-        } else {
-            if (mMediaPlayer.isPlaying()) {
-                mState = PlaybackStateCompat.STATE_BUFFERING;
-            }
-            mMediaPlayer.seekTo(position);
-            if (mCallback != null) {
-                mCallback.onPlaybackStatusChanged(mState);
-            }
-        }
-    }
-
-    public void setCallback(Callback callback) {
-        this.mCallback = callback;
-    }
-
-    /**
-     * Try to get the system audio focus.
-     */
-    private void tryToGetAudioFocus() {
-        Log.d(TAG, "tryToGetAudioFocus");
-        int result = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
-                AudioManager.AUDIOFOCUS_GAIN);
-        mAudioFocus = (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
-                ? AUDIO_FOCUSED : AUDIO_NO_FOCUS_NO_DUCK;
-    }
-
-    /**
-     * Give up the audio focus.
-     */
-    private void giveUpAudioFocus() {
-        Log.d(TAG, "giveUpAudioFocus");
-        if (mAudioManager.abandonAudioFocus(this) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
-            mAudioFocus = AUDIO_NO_FOCUS_NO_DUCK;
-        }
-    }
-
-    /**
-     * Reconfigures MediaPlayer according to audio focus settings and
-     * starts/restarts it. This method starts/restarts the MediaPlayer
-     * respecting the current audio focus state. So if we have focus, it will
-     * play normally; if we don't have focus, it will either leave the
-     * MediaPlayer paused or set it to a low volume, depending on what is
-     * allowed by the current focus settings. This method assumes mPlayer !=
-     * null, so if you are calling it, you have to do so from a context where
-     * you are sure this is the case.
-     */
-    private void configMediaPlayerState() {
-        Log.d(TAG, "configMediaPlayerState. mAudioFocus=" + mAudioFocus);
-        if (mAudioFocus == AUDIO_NO_FOCUS_NO_DUCK) {
-            // If we don't have audio focus and can't duck, we have to pause,
-            if (mState == PlaybackStateCompat.STATE_PLAYING) {
-                pause();
-            }
-        } else {  // we have audio focus:
-            if (mAudioFocus == AUDIO_NO_FOCUS_CAN_DUCK) {
-                mMediaPlayer.setVolume(VOLUME_DUCK, VOLUME_DUCK); // we'll be relatively quiet
-            } else {
-                if (mMediaPlayer != null) {
-                    mMediaPlayer.setVolume(VOLUME_NORMAL, VOLUME_NORMAL); // we can be loud again
-                } // else do something for remote client.
-            }
-            // If we were playing when we lost focus, we need to resume playing.
-            if (mPlayOnFocusGain) {
-                if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
-                    Log.d(TAG, "configMediaPlayerState startMediaPlayer. seeking to "
-                            + mCurrentPosition);
-                    if (mCurrentPosition == mMediaPlayer.getCurrentPosition()) {
-                        mMediaPlayer.start();
-                        mState = PlaybackStateCompat.STATE_PLAYING;
-                    } else {
-                        mMediaPlayer.seekTo(mCurrentPosition);
-                        mState = PlaybackStateCompat.STATE_BUFFERING;
-                    }
-                }
-                mPlayOnFocusGain = false;
-            }
-        }
-        if (mCallback != null) {
-            mCallback.onPlaybackStatusChanged(mState);
-        }
-    }
-
-    /**
-     * Called by AudioManager on audio focus changes.
-     * Implementation of {@link android.media.AudioManager.OnAudioFocusChangeListener}.
-     */
-    @Override
-    public void onAudioFocusChange(int focusChange) {
-        Log.d(TAG, "onAudioFocusChange. focusChange=" + focusChange);
-        if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
-            // We have gained focus:
-            mAudioFocus = AUDIO_FOCUSED;
-
-        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS
-                || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
-                || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
-            // We have lost focus. If we can duck (low playback volume), we can keep playing.
-            // Otherwise, we need to pause the playback.
-            boolean canDuck = focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
-            mAudioFocus = canDuck ? AUDIO_NO_FOCUS_CAN_DUCK : AUDIO_NO_FOCUS_NO_DUCK;
-
-            // If we are playing, we need to reset media player by calling configMediaPlayerState
-            // with mAudioFocus properly set.
-            if (mState == PlaybackStateCompat.STATE_PLAYING && !canDuck) {
-                // If we don't have audio focus and can't duck, we save the information that
-                // we were playing, so that we can resume playback once we get the focus back.
-                mPlayOnFocusGain = true;
-            }
-        } else {
-            Log.e(TAG, "onAudioFocusChange: Ignoring unsupported focusChange: " + focusChange);
-        }
-        configMediaPlayerState();
-    }
-
-    /**
-     * Called when MediaPlayer has completed a seek.
-     *
-     * @see android.media.MediaPlayer.OnSeekCompleteListener
-     */
-    @Override
-    public void onSeekComplete(MediaPlayer player) {
-        Log.d(TAG, "onSeekComplete from MediaPlayer:" + player.getCurrentPosition());
-        mCurrentPosition = player.getCurrentPosition();
-        if (mState == PlaybackStateCompat.STATE_BUFFERING) {
-            mMediaPlayer.start();
-            mState = PlaybackStateCompat.STATE_PLAYING;
-        }
-        if (mCallback != null) {
-            mCallback.onPlaybackStatusChanged(mState);
-        }
-    }
-
-    /**
-     * Called when media player is done playing current song.
-     *
-     * @see android.media.MediaPlayer.OnCompletionListener
-     */
-    @Override
-    public void onCompletion(MediaPlayer player) {
-        Log.d(TAG, "onCompletion from MediaPlayer");
-        // The media player finished playing the current song, so we go ahead
-        // and start the next.
-        if (mCallback != null) {
-            mCallback.onCompletion();
-        }
-    }
-
-    /**
-     * Called when media player is done preparing.
-     *
-     * @see android.media.MediaPlayer.OnPreparedListener
-     */
-    @Override
-    public void onPrepared(MediaPlayer player) {
-        Log.d(TAG, "onPrepared from MediaPlayer");
-        // The media player is done preparing. That means we can start playing if we
-        // have audio focus.
-        configMediaPlayerState();
-    }
-
-    /**
-     * Called when there's an error playing media. When this happens, the media
-     * player goes to the Error state. We warn the user about the error and
-     * reset the media player.
-     *
-     * @see android.media.MediaPlayer.OnErrorListener
-     */
-    @Override
-    public boolean onError(MediaPlayer player, int what, int extra) {
-        Log.e(TAG, "Media player error: what=" + what + ", extra=" + extra);
-        if (mCallback != null) {
-            mCallback.onError("MediaPlayer error " + what + " (" + extra + ")");
-        }
-        return true; // true indicates we handled the error
-    }
-
-    /**
-     * Makes sure the media player exists and has been reset. This will create
-     * the media player if needed, or reset the existing media player if one
-     * already exists.
-     */
-    private void createMediaPlayerIfNeeded() {
-        Log.d(TAG, "createMediaPlayerIfNeeded. needed? " + (mMediaPlayer == null));
-        if (mMediaPlayer == null) {
-            mMediaPlayer = new MediaPlayer();
-
-            // Make sure the media player will acquire a wake-lock while
-            // playing. If we don't do that, the CPU might go to sleep while the
-            // song is playing, causing playback to stop.
-            mMediaPlayer.setWakeMode(mService.getApplicationContext(),
-                    PowerManager.PARTIAL_WAKE_LOCK);
-
-            // we want the media player to notify us when it's ready preparing,
-            // and when it's done playing:
-            mMediaPlayer.setOnPreparedListener(this);
-            mMediaPlayer.setOnCompletionListener(this);
-            mMediaPlayer.setOnErrorListener(this);
-            mMediaPlayer.setOnSeekCompleteListener(this);
-        } else {
-            mMediaPlayer.reset();
-        }
-    }
-
-    /**
-     * Releases resources used by the service for playback. This includes the
-     * "foreground service" status, the wake locks and possibly the MediaPlayer.
-     *
-     * @param releaseMediaPlayer Indicates whether the Media Player should also
-     *                           be released or not.
-     */
-    private void relaxResources(boolean releaseMediaPlayer) {
-        Log.d(TAG, "relaxResources. releaseMediaPlayer=" + releaseMediaPlayer);
-
-        mService.stopForeground(true);
-
-        // stop and release the Media Player, if it's available
-        if (releaseMediaPlayer && mMediaPlayer != null) {
-            mMediaPlayer.reset();
-            mMediaPlayer.release();
-            mMediaPlayer = null;
-        }
-
-        // we can also release the Wifi lock, if we're holding it
-        if (mWifiLock.isHeld()) {
-            mWifiLock.release();
-        }
-    }
-}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java
deleted file mode 100644
index 7eead43..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * 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.mediabrowserservice.model;
-
-import android.os.AsyncTask;
-import android.support.v4.media.MediaMetadataCompat;
-import android.util.Log;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-
-/**
- * Utility class to get a list of MusicTrack's based on a server-side JSON
- * configuration.
- *
- * In a real application this class may pull data from a remote server, as we do here,
- * or potentially use {@link android.provider.MediaStore} to locate media files located on
- * the device.
- */
-public class MusicProvider {
-
-    private static final String TAG = MusicProvider.class.getSimpleName();
-
-    public static final String MEDIA_ID_ROOT = "__ROOT__";
-    public static final String MEDIA_ID_EMPTY_ROOT = "__EMPTY__";
-
-    private static final String CATALOG_URL =
-            "https://storage.googleapis.com/automotive-media/music.json";
-
-    private static final String JSON_MUSIC = "music";
-    private static final String JSON_TITLE = "title";
-    private static final String JSON_ALBUM = "album";
-    private static final String JSON_ARTIST = "artist";
-    private static final String JSON_GENRE = "genre";
-    private static final String JSON_SOURCE = "source";
-    private static final String JSON_IMAGE = "image";
-    private static final String JSON_TRACK_NUMBER = "trackNumber";
-    private static final String JSON_TOTAL_TRACK_COUNT = "totalTrackCount";
-    private static final String JSON_DURATION = "duration";
-
-    // Categorized caches for music track data:
-    private final LinkedHashMap<String, MediaMetadataCompat> mMusicListById;
-
-    private enum State {
-        NON_INITIALIZED, INITIALIZING, INITIALIZED
-    }
-
-    private volatile State mCurrentState = State.NON_INITIALIZED;
-
-    /**
-     * Callback used by MusicService.
-     */
-    public interface Callback {
-        void onMusicCatalogReady(boolean success);
-    }
-
-    public MusicProvider() {
-        mMusicListById = new LinkedHashMap<>();
-    }
-
-    public Iterable<MediaMetadataCompat> getAllMusics() {
-        if (mCurrentState != State.INITIALIZED || mMusicListById.isEmpty()) {
-            return Collections.emptyList();
-        }
-        return mMusicListById.values();
-    }
-
-    /**
-     * Return the MediaMetadata for the given musicID.
-     *
-     * @param musicId The unique music ID.
-     */
-    public MediaMetadataCompat getMusic(String musicId) {
-        return mMusicListById.containsKey(musicId) ? mMusicListById.get(musicId) : null;
-    }
-
-    /**
-     * Update the metadata associated with a musicId. If the musicId doesn't exist, the
-     * update is dropped. (That is, it does not create a new mediaId.)
-     * @param musicId The ID
-     * @param metadata New Metadata to associate with it
-     */
-    public synchronized void updateMusic(String musicId, MediaMetadataCompat metadata) {
-        MediaMetadataCompat track = mMusicListById.get(musicId);
-        if (track != null) {
-            mMusicListById.put(musicId, metadata);
-        }
-    }
-
-    public boolean isInitialized() {
-        return mCurrentState == State.INITIALIZED;
-    }
-
-    /**
-     * Get the list of music tracks from a server and caches the track information
-     * for future reference, keying tracks by musicId and grouping by genre.
-     */
-    public void retrieveMediaAsync(final Callback callback) {
-        Log.d(TAG, "retrieveMediaAsync called");
-        if (mCurrentState == State.INITIALIZED) {
-            // Already initialized, so call back immediately.
-            callback.onMusicCatalogReady(true);
-            return;
-        }
-
-        // Asynchronously load the music catalog in a separate thread
-        new AsyncTask<Void, Void, State>() {
-            @Override
-            protected State doInBackground(Void... params) {
-                retrieveMedia();
-                return mCurrentState;
-            }
-
-            @Override
-            protected void onPostExecute(State current) {
-                if (callback != null) {
-                    callback.onMusicCatalogReady(current == State.INITIALIZED);
-                }
-            }
-        }.execute();
-    }
-
-    private synchronized void retrieveMedia() {
-        try {
-            if (mCurrentState == State.NON_INITIALIZED) {
-                mCurrentState = State.INITIALIZING;
-
-                int slashPos = CATALOG_URL.lastIndexOf('/');
-                String path = CATALOG_URL.substring(0, slashPos + 1);
-                JSONObject jsonObj = fetchJSONFromUrl(CATALOG_URL);
-                if (jsonObj == null) {
-                    return;
-                }
-                JSONArray tracks = jsonObj.getJSONArray(JSON_MUSIC);
-                if (tracks != null) {
-                    for (int j = tracks.length() - 1; j >= 0; j--) {
-                        MediaMetadataCompat item = buildFromJSON(tracks.getJSONObject(j), path);
-                        String musicId = item.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID);
-                        mMusicListById.put(musicId, item);
-                    }
-                }
-                mCurrentState = State.INITIALIZED;
-            }
-        } catch (JSONException jsonException) {
-            Log.e(TAG, "Could not retrieve music list", jsonException);
-        } finally {
-            if (mCurrentState != State.INITIALIZED) {
-                // Something bad happened, so we reset state to NON_INITIALIZED to allow
-                // retries (eg if the network connection is temporary unavailable)
-                mCurrentState = State.NON_INITIALIZED;
-            }
-        }
-    }
-
-    private MediaMetadataCompat buildFromJSON(JSONObject json, String basePath)
-            throws JSONException {
-
-        String title = json.getString(JSON_TITLE);
-        String album = json.getString(JSON_ALBUM);
-        String artist = json.getString(JSON_ARTIST);
-        String genre = json.getString(JSON_GENRE);
-        String source = json.getString(JSON_SOURCE);
-        String iconUrl = json.getString(JSON_IMAGE);
-        int trackNumber = json.getInt(JSON_TRACK_NUMBER);
-        int totalTrackCount = json.getInt(JSON_TOTAL_TRACK_COUNT);
-        int duration = json.getInt(JSON_DURATION) * 1000; // ms
-
-        Log.d(TAG, "Found music track: " + json);
-
-        // Media is stored relative to JSON file
-        if (!source.startsWith("https")) {
-            source = basePath + source;
-        }
-        if (!iconUrl.startsWith("https")) {
-            iconUrl = basePath + iconUrl;
-        }
-        // Since we don't have a unique ID in the server, we fake one using the hashcode of
-        // the music source. In a real world app, this could come from the server.
-        String id = String.valueOf(source.hashCode());
-
-        // Adding the music source to the MediaMetadata (and consequently using it in the
-        // mediaSession.setMetadata) is not a good idea for a real world music app, because
-        // the session metadata can be accessed by notification listeners. This is done in this
-        // sample for convenience only.
-        return new MediaMetadataCompat.Builder()
-                .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, id)
-                .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI, source)
-                .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, album)
-                .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
-                .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration)
-                .putString(MediaMetadataCompat.METADATA_KEY_GENRE, genre)
-                .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, iconUrl)
-                .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
-                .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, trackNumber)
-                .putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, totalTrackCount)
-                .build();
-    }
-
-    /**
-     * Download a JSON file from a server, parse the content and return the JSON
-     * object.
-     *
-     * @return result JSONObject containing the parsed representation.
-     */
-    private JSONObject fetchJSONFromUrl(String urlString) {
-        InputStream inputStream = null;
-        try {
-            URL url = new URL(urlString);
-            URLConnection urlConnection = url.openConnection();
-            inputStream = new BufferedInputStream(urlConnection.getInputStream());
-            BufferedReader reader = new BufferedReader(new InputStreamReader(
-                    urlConnection.getInputStream(), "iso-8859-1"));
-            StringBuilder stringBuilder = new StringBuilder();
-            String line;
-            while ((line = reader.readLine()) != null) {
-                stringBuilder.append(line);
-            }
-            return new JSONObject(stringBuilder.toString());
-        } catch (IOException | JSONException exception) {
-            Log.e(TAG, "Failed to parse the json for media list", exception);
-            return null;
-        } finally {
-            // If the inputStream was opened, try to close it now.
-            if (inputStream != null) {
-                try {
-                    inputStream.close();
-                } catch (IOException ignored) {
-                    // Ignore the exception since there's nothing left to do with the stream
-                }
-            }
-        }
-    }
-}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/client/MediaBrowserAdapter.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/client/MediaBrowserAdapter.java
new file mode 100644
index 0000000..d2f0b7f
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/client/MediaBrowserAdapter.java
@@ -0,0 +1,297 @@
+/*
+ * 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.mediasession.client;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.RemoteException;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.media.MediaBrowserCompat;
+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;
+import android.util.Log;
+
+import com.example.android.mediasession.service.MusicService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Adapter for a MediaBrowser that handles connecting, disconnecting,
+ * and basic browsing.
+ */
+public class MediaBrowserAdapter {
+
+    private static final String TAG = MediaBrowserAdapter.class.getSimpleName();
+
+    /**
+     * Helper class for easily subscribing to changes in a MediaBrowserService connection.
+     */
+    public static abstract class MediaBrowserChangeListener {
+
+        public void onConnected(@Nullable MediaControllerCompat mediaController) {
+        }
+
+        public void onMetadataChanged(@Nullable MediaMetadataCompat mediaMetadata) {
+        }
+
+        public void onPlaybackStateChanged(@Nullable PlaybackStateCompat playbackState) {
+        }
+    }
+
+    private final InternalState mState;
+
+    private final Context mContext;
+    private final List<MediaBrowserChangeListener> mListeners = new ArrayList<>();
+
+    private final MediaBrowserConnectionCallback mMediaBrowserConnectionCallback =
+            new MediaBrowserConnectionCallback();
+    private final MediaControllerCallback mMediaControllerCallback =
+            new MediaControllerCallback();
+    private final MediaBrowserSubscriptionCallback mMediaBrowserSubscriptionCallback =
+            new MediaBrowserSubscriptionCallback();
+
+    private MediaBrowserCompat mMediaBrowser;
+
+    @Nullable
+    private MediaControllerCompat mMediaController;
+
+    public MediaBrowserAdapter(Context context) {
+        mContext = context;
+        mState = new InternalState();
+    }
+
+    public void onStart() {
+        if (mMediaBrowser == null) {
+            mMediaBrowser =
+                    new MediaBrowserCompat(
+                            mContext,
+                            new ComponentName(mContext, MusicService.class),
+                            mMediaBrowserConnectionCallback,
+                            null);
+            mMediaBrowser.connect();
+        }
+        Log.d(TAG, "onStart: Creating MediaBrowser, and connecting");
+    }
+
+    public void onStop() {
+        if (mMediaController != null) {
+            mMediaController.unregisterCallback(mMediaControllerCallback);
+            mMediaController = null;
+        }
+        if (mMediaBrowser != null && mMediaBrowser.isConnected()) {
+            mMediaBrowser.disconnect();
+            mMediaBrowser = null;
+        }
+        resetState();
+        Log.d(TAG, "onStop: Releasing MediaController, Disconnecting from MediaBrowser");
+    }
+
+    /**
+     * The internal state of the app needs to revert to what it looks like when it started before
+     * any connections to the {@link MusicService} happens via the {@link MediaSessionCompat}.
+     */
+    private void resetState() {
+        mState.reset();
+        performOnAllListeners(new ListenerCommand() {
+            @Override
+            public void perform(@NonNull MediaBrowserChangeListener listener) {
+                listener.onPlaybackStateChanged(null);
+            }
+        });
+        Log.d(TAG, "resetState: ");
+    }
+
+    public MediaControllerCompat.TransportControls getTransportControls() {
+        if (mMediaController == null) {
+            Log.d(TAG, "getTransportControls: MediaController is null!");
+            throw new IllegalStateException();
+        }
+        return mMediaController.getTransportControls();
+    }
+
+    public void addListener(MediaBrowserChangeListener listener) {
+        if (listener != null) {
+            mListeners.add(listener);
+        }
+    }
+
+    public void removeListener(MediaBrowserChangeListener listener) {
+        if (listener != null) {
+            if (mListeners.contains(listener)) {
+                mListeners.remove(listener);
+            }
+        }
+    }
+
+    public void performOnAllListeners(@NonNull ListenerCommand command) {
+        for (MediaBrowserChangeListener listener : mListeners) {
+            if (listener != null) {
+                try {
+                    command.perform(listener);
+                } catch (Exception e) {
+                    removeListener(listener);
+                }
+            }
+        }
+    }
+
+    public interface ListenerCommand {
+
+        void perform(@NonNull MediaBrowserChangeListener listener);
+    }
+
+    // Receives callbacks from the MediaBrowser when it has successfully connected to the
+    // MediaBrowserService (MusicService).
+    public class MediaBrowserConnectionCallback extends MediaBrowserCompat.ConnectionCallback {
+
+        // Happens as a result of onStart().
+        @Override
+        public void onConnected() {
+            try {
+                // Get a MediaController for the MediaSession.
+                mMediaController = new MediaControllerCompat(mContext,
+                                                             mMediaBrowser.getSessionToken());
+                mMediaController.registerCallback(mMediaControllerCallback);
+
+                // Sync existing MediaSession state to the UI.
+                mMediaControllerCallback.onMetadataChanged(
+                        mMediaController.getMetadata());
+                mMediaControllerCallback
+                        .onPlaybackStateChanged(mMediaController.getPlaybackState());
+
+                performOnAllListeners(new ListenerCommand() {
+                    @Override
+                    public void perform(@NonNull MediaBrowserChangeListener listener) {
+                        listener.onConnected(mMediaController);
+                    }
+                });
+            } catch (RemoteException e) {
+                Log.d(TAG, String.format("onConnected: Problem: %s", e.toString()));
+                throw new RuntimeException(e);
+            }
+
+            mMediaBrowser.subscribe(mMediaBrowser.getRoot(), mMediaBrowserSubscriptionCallback);
+        }
+    }
+
+    // Receives callbacks from the MediaBrowser when the MediaBrowserService has loaded new media
+    // that is ready for playback.
+    public class MediaBrowserSubscriptionCallback extends MediaBrowserCompat.SubscriptionCallback {
+
+        @Override
+        public void onChildrenLoaded(@NonNull String parentId,
+                                     @NonNull List<MediaBrowserCompat.MediaItem> children) {
+            assert mMediaController != null;
+
+            // Queue up all media items for this simple sample.
+            for (final MediaBrowserCompat.MediaItem mediaItem : children) {
+                mMediaController.addQueueItem(mediaItem.getDescription());
+            }
+
+            // Call "playFromMedia" so the UI is updated.
+            mMediaController.getTransportControls().prepare();
+        }
+    }
+
+    // Receives callbacks from the MediaController and updates the UI state,
+    // i.e.: Which is the current item, whether it's playing or paused, etc.
+    public class MediaControllerCallback extends MediaControllerCompat.Callback {
+
+        @Override
+        public void onMetadataChanged(final MediaMetadataCompat metadata) {
+            // Filtering out needless updates, given that the metadata has not changed.
+            if (isMediaIdSame(metadata, mState.getMediaMetadata())) {
+                Log.d(TAG, "onMetadataChanged: Filtering out needless onMetadataChanged() update");
+                return;
+            } else {
+                mState.setMediaMetadata(metadata);
+            }
+            performOnAllListeners(new ListenerCommand() {
+                @Override
+                public void perform(@NonNull MediaBrowserChangeListener listener) {
+                    listener.onMetadataChanged(metadata);
+                }
+            });
+        }
+
+        @Override
+        public void onPlaybackStateChanged(@Nullable final PlaybackStateCompat state) {
+            mState.setPlaybackState(state);
+            performOnAllListeners(new ListenerCommand() {
+                @Override
+                public void perform(@NonNull MediaBrowserChangeListener listener) {
+                    listener.onPlaybackStateChanged(state);
+                }
+            });
+        }
+
+        // This might happen if the MusicService is killed while the Activity is in the
+        // foreground and onStart() has been called (but not onStop()).
+        @Override
+        public void onSessionDestroyed() {
+            resetState();
+            onPlaybackStateChanged(null);
+            Log.d(TAG, "onSessionDestroyed: MusicService is dead!!!");
+        }
+
+        private boolean isMediaIdSame(MediaMetadataCompat currentMedia,
+                                     MediaMetadataCompat newMedia) {
+            if (currentMedia == null || newMedia == null) {
+                return false;
+            }
+            String newMediaId =
+                    newMedia.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID);
+            String currentMediaId =
+                    currentMedia.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID);
+            return newMediaId.equals(currentMediaId);
+        }
+
+    }
+
+    // A holder class that contains the internal state.
+    public class InternalState {
+
+        private PlaybackStateCompat playbackState;
+        private MediaMetadataCompat mediaMetadata;
+
+        public void reset() {
+            playbackState = null;
+            mediaMetadata = null;
+        }
+
+        public PlaybackStateCompat getPlaybackState() {
+            return playbackState;
+        }
+
+        public void setPlaybackState(PlaybackStateCompat playbackState) {
+            this.playbackState = playbackState;
+        }
+
+        public MediaMetadataCompat getMediaMetadata() {
+            return mediaMetadata;
+        }
+
+        public void setMediaMetadata(MediaMetadataCompat mediaMetadata) {
+            this.mediaMetadata = mediaMetadata;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/MusicService.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/MusicService.java
new file mode 100644
index 0000000..5d98bc2
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/MusicService.java
@@ -0,0 +1,244 @@
+/*
+ * 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.mediasession.service;
+
+import android.app.Notification;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.media.MediaBrowserCompat;
+import android.support.v4.media.MediaBrowserServiceCompat;
+import android.support.v4.media.MediaDescriptionCompat;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
+import android.util.Log;
+
+import com.example.android.mediasession.service.contentcatalogs.MusicLibrary;
+import com.example.android.mediasession.service.notifications.MediaNotificationManager;
+import com.example.android.mediasession.service.players.MediaPlayerAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MusicService extends MediaBrowserServiceCompat {
+
+    private static final String TAG = MusicService.class.getSimpleName();
+
+    private MediaSessionCompat mSession;
+    private PlayerAdapter mPlayback;
+    private MediaNotificationManager mMediaNotificationManager;
+    private MediaSessionCallback mCallback;
+    private boolean mServiceInStartedState;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        // Create a new MediaSession.
+        mSession = new MediaSessionCompat(this, "MusicService");
+        mCallback = new MediaSessionCallback();
+        mSession.setCallback(mCallback);
+        mSession.setFlags(
+                MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
+                MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS |
+                MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
+        setSessionToken(mSession.getSessionToken());
+
+        mMediaNotificationManager = new MediaNotificationManager(this);
+
+        mPlayback = new MediaPlayerAdapter(this, new MediaPlayerListener());
+        Log.d(TAG, "onCreate: MusicService creating MediaSession, and MediaNotificationManager");
+    }
+
+    @Override
+    public void onTaskRemoved(Intent rootIntent) {
+        super.onTaskRemoved(rootIntent);
+        stopSelf();
+    }
+
+    @Override
+    public void onDestroy() {
+        mMediaNotificationManager.onDestroy();
+        mPlayback.stop();
+        mSession.release();
+        Log.d(TAG, "onDestroy: MediaPlayerAdapter stopped, and MediaSession released");
+    }
+
+    @Override
+    public BrowserRoot onGetRoot(@NonNull String clientPackageName,
+                                 int clientUid,
+                                 Bundle rootHints) {
+        return new BrowserRoot(MusicLibrary.getRoot(), null);
+    }
+
+    @Override
+    public void onLoadChildren(
+            @NonNull final String parentMediaId,
+            @NonNull final Result<List<MediaBrowserCompat.MediaItem>> result) {
+        result.sendResult(MusicLibrary.getMediaItems());
+    }
+
+    // MediaSession Callback: Transport Controls -> MediaPlayerAdapter
+    public class MediaSessionCallback extends MediaSessionCompat.Callback {
+        private final List<MediaSessionCompat.QueueItem> mPlaylist = new ArrayList<>();
+        private int mQueueIndex = -1;
+        private MediaMetadataCompat mPreparedMedia;
+
+        @Override
+        public void onAddQueueItem(MediaDescriptionCompat description) {
+            mPlaylist.add(new MediaSessionCompat.QueueItem(description, description.hashCode()));
+            mQueueIndex = (mQueueIndex == -1) ? 0 : mQueueIndex;
+        }
+
+        @Override
+        public void onRemoveQueueItem(MediaDescriptionCompat description) {
+            mPlaylist.remove(new MediaSessionCompat.QueueItem(description, description.hashCode()));
+            mQueueIndex = (mPlaylist.isEmpty()) ? -1 : mQueueIndex;
+        }
+
+        @Override
+        public void onPrepare() {
+            if (mQueueIndex < 0 && mPlaylist.isEmpty()) {
+                // Nothing to play.
+                return;
+            }
+
+            final String mediaId = mPlaylist.get(mQueueIndex).getDescription().getMediaId();
+            mPreparedMedia = MusicLibrary.getMetadata(MusicService.this, mediaId);
+            mSession.setMetadata(mPreparedMedia);
+
+            if (!mSession.isActive()) {
+                mSession.setActive(true);
+            }
+        }
+
+        @Override
+        public void onPlay() {
+            if (!isReadyToPlay()) {
+                // Nothing to play.
+                return;
+            }
+
+            if (mPreparedMedia == null) {
+                onPrepare();
+            }
+
+            mPlayback.playFromMedia(mPreparedMedia);
+            Log.d(TAG, "onPlayFromMediaId: MediaSession active");
+        }
+
+        @Override
+        public void onPause() {
+            mPlayback.pause();
+        }
+
+        @Override
+        public void onStop() {
+            mPlayback.stop();
+            mSession.setActive(false);
+        }
+
+        @Override
+        public void onSkipToNext() {
+            mQueueIndex = (++mQueueIndex % mPlaylist.size());
+            mPreparedMedia = null;
+            onPlay();
+        }
+
+        @Override
+        public void onSkipToPrevious() {
+            mQueueIndex = mQueueIndex > 0 ? mQueueIndex - 1 : mPlaylist.size() - 1;
+            mPreparedMedia = null;
+            onPlay();
+        }
+
+        @Override
+        public void onSeekTo(long pos) {
+            mPlayback.seekTo(pos);
+        }
+
+        private boolean isReadyToPlay() {
+            return (!mPlaylist.isEmpty());
+        }
+    }
+
+    // MediaPlayerAdapter Callback: MediaPlayerAdapter state -> MusicService.
+    public class MediaPlayerListener extends PlaybackInfoListener {
+
+        private final ServiceManager mServiceManager;
+
+        MediaPlayerListener() {
+            mServiceManager = new ServiceManager();
+        }
+
+        @Override
+        public void onPlaybackStateChange(PlaybackStateCompat state) {
+            // Report the state to the MediaSession.
+            mSession.setPlaybackState(state);
+
+            // Manage the started state of this service.
+            switch (state.getState()) {
+                case PlaybackStateCompat.STATE_PLAYING:
+                    mServiceManager.moveServiceToStartedState(state);
+                    break;
+                case PlaybackStateCompat.STATE_PAUSED:
+                    mServiceManager.updateNotificationForPause(state);
+                    break;
+                case PlaybackStateCompat.STATE_STOPPED:
+                    mServiceManager.moveServiceOutOfStartedState(state);
+                    break;
+            }
+        }
+
+        class ServiceManager {
+
+            private void moveServiceToStartedState(PlaybackStateCompat state) {
+                Notification notification =
+                        mMediaNotificationManager.getNotification(
+                                mPlayback.getCurrentMedia(), state, getSessionToken());
+
+                if (!mServiceInStartedState) {
+                    ContextCompat.startForegroundService(
+                            MusicService.this,
+                            new Intent(MusicService.this, MusicService.class));
+                    mServiceInStartedState = true;
+                }
+
+                startForeground(MediaNotificationManager.NOTIFICATION_ID, notification);
+            }
+
+            private void updateNotificationForPause(PlaybackStateCompat state) {
+                stopForeground(false);
+                Notification notification =
+                        mMediaNotificationManager.getNotification(
+                                mPlayback.getCurrentMedia(), state, getSessionToken());
+                mMediaNotificationManager.getNotificationManager()
+                        .notify(MediaNotificationManager.NOTIFICATION_ID, notification);
+            }
+
+            private void moveServiceOutOfStartedState(PlaybackStateCompat state) {
+                stopForeground(true);
+                stopSelf();
+                mServiceInStartedState = false;
+            }
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/PlaybackInfoListener.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/PlaybackInfoListener.java
new file mode 100644
index 0000000..f19abd2
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/PlaybackInfoListener.java
@@ -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.mediasession.service;
+
+import android.support.v4.media.session.PlaybackStateCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+
+import com.example.android.mediasession.service.players.MediaPlayerAdapter;
+
+/**
+ * Listener to provide state updates from {@link MediaPlayerAdapter} (the media player)
+ * to {@link MusicService} (the service that holds our {@link MediaSessionCompat}.
+ */
+public abstract class PlaybackInfoListener {
+
+    public abstract void onPlaybackStateChange(PlaybackStateCompat state);
+
+    public void onPlaybackCompleted() {
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/PlayerAdapter.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/PlayerAdapter.java
new file mode 100644
index 0000000..83c810e
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/PlayerAdapter.java
@@ -0,0 +1,173 @@
+/*
+ * 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.mediasession.service;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.net.wifi.WifiManager;
+import android.support.annotation.NonNull;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
+
+/**
+ * Abstract player implementation that handles playing music with proper handling of headphones
+ * and audio focus.
+ */
+public abstract class PlayerAdapter {
+
+    private static final float MEDIA_VOLUME_DEFAULT = 1.0f;
+    private static final float MEDIA_VOLUME_DUCK = 0.2f;
+
+    private static final IntentFilter AUDIO_NOISY_INTENT_FILTER =
+            new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+
+    private boolean mAudioNoisyReceiverRegistered = false;
+    private final BroadcastReceiver mAudioNoisyReceiver =
+            new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
+                        if (isPlaying()) {
+                            pause();
+                        }
+                    }
+                }
+            };
+
+    private final Context mApplicationContext;
+    private final AudioManager mAudioManager;
+    private final AudioFocusHelper mAudioFocusHelper;
+
+    private boolean mPlayOnAudioFocus = false;
+
+    public PlayerAdapter(@NonNull Context context) {
+        mApplicationContext = context.getApplicationContext();
+        mAudioManager = (AudioManager) mApplicationContext.getSystemService(Context.AUDIO_SERVICE);
+        mAudioFocusHelper = new AudioFocusHelper();
+    }
+
+    public abstract void playFromMedia(MediaMetadataCompat metadata);
+
+    public abstract MediaMetadataCompat getCurrentMedia();
+
+    public abstract boolean isPlaying();
+
+    public final void play() {
+        if (mAudioFocusHelper.requestAudioFocus()) {
+            registerAudioNoisyReceiver();
+            onPlay();
+        }
+    }
+
+    /**
+     * Called when media is ready to be played and indicates the app has audio focus.
+     */
+    protected abstract void onPlay();
+
+    public final void pause() {
+        if (!mPlayOnAudioFocus) {
+            mAudioFocusHelper.abandonAudioFocus();
+        }
+
+        unregisterAudioNoisyReceiver();
+        onPause();
+    }
+
+    /**
+     * Called when media must be paused.
+     */
+    protected abstract void onPause();
+
+    public final void stop() {
+        mAudioFocusHelper.abandonAudioFocus();
+        unregisterAudioNoisyReceiver();
+        onStop();
+    }
+
+    /**
+     * Called when the media must be stopped. The player should clean up resources at this
+     * point.
+     */
+    protected abstract void onStop();
+
+    public abstract void seekTo(long position);
+
+    public abstract void setVolume(float volume);
+
+    private void registerAudioNoisyReceiver() {
+        if (!mAudioNoisyReceiverRegistered) {
+            mApplicationContext.registerReceiver(mAudioNoisyReceiver, AUDIO_NOISY_INTENT_FILTER);
+            mAudioNoisyReceiverRegistered = true;
+        }
+    }
+
+    private void unregisterAudioNoisyReceiver() {
+        if (mAudioNoisyReceiverRegistered) {
+            mApplicationContext.unregisterReceiver(mAudioNoisyReceiver);
+            mAudioNoisyReceiverRegistered = false;
+        }
+    }
+
+    /**
+     * Helper class for managing audio focus related tasks.
+     */
+    private final class AudioFocusHelper
+            implements AudioManager.OnAudioFocusChangeListener {
+
+        private boolean requestAudioFocus() {
+            final int result = mAudioManager.requestAudioFocus(this,
+                    AudioManager.STREAM_MUSIC,
+                    AudioManager.AUDIOFOCUS_GAIN);
+            return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+        }
+
+        private void abandonAudioFocus() {
+            mAudioManager.abandonAudioFocus(this);
+        }
+
+        @Override
+        public void onAudioFocusChange(int focusChange) {
+            switch (focusChange) {
+                case AudioManager.AUDIOFOCUS_GAIN:
+                    if (mPlayOnAudioFocus && !isPlaying()) {
+                        play();
+                    } else if (isPlaying()) {
+                        setVolume(MEDIA_VOLUME_DEFAULT);
+                    }
+                    mPlayOnAudioFocus = false;
+                    break;
+                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                    setVolume(MEDIA_VOLUME_DUCK);
+                    break;
+                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                    if (isPlaying()) {
+                        mPlayOnAudioFocus = true;
+                        pause();
+                    }
+                    break;
+                case AudioManager.AUDIOFOCUS_LOSS:
+                    mAudioManager.abandonAudioFocus(this);
+                    mPlayOnAudioFocus = false;
+                    stop();
+                    break;
+            }
+        }
+    }
+}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/contentcatalogs/MusicLibrary.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/contentcatalogs/MusicLibrary.java
new file mode 100644
index 0000000..dacb009
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/contentcatalogs/MusicLibrary.java
@@ -0,0 +1,154 @@
+/*
+ * 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.mediasession.service.contentcatalogs;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.support.v4.media.MediaBrowserCompat;
+import android.support.v4.media.MediaMetadataCompat;
+
+import com.example.android.mediasession.BuildConfig;
+import com.example.android.mediasession.R;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+
+
+public class MusicLibrary {
+
+    private static final TreeMap<String, MediaMetadataCompat> music = new TreeMap<>();
+    private static final HashMap<String, Integer> albumRes = new HashMap<>();
+    private static final HashMap<String, String> musicFileName = new HashMap<>();
+
+    static {
+        createMediaMetadataCompat(
+                "Jazz_In_Paris",
+                "Jazz in Paris",
+                "Media Right Productions",
+                "Jazz & Blues",
+                "Jazz",
+                103,
+                TimeUnit.SECONDS,
+                "jazz_in_paris.mp3",
+                R.drawable.album_jazz_blues,
+                "album_jazz_blues");
+        createMediaMetadataCompat(
+                "The_Coldest_Shoulder",
+                "The Coldest Shoulder",
+                "The 126ers",
+                "Youtube Audio Library Rock 2",
+                "Rock",
+                160,
+                TimeUnit.SECONDS,
+                "the_coldest_shoulder.mp3",
+                R.drawable.album_youtube_audio_library_rock_2,
+                "album_youtube_audio_library_rock_2");
+    }
+
+    public static String getRoot() {
+        return "root";
+    }
+
+    private static String getAlbumArtUri(String albumArtResName) {
+        return ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+                BuildConfig.APPLICATION_ID + "/drawable/" + albumArtResName;
+    }
+
+    public static String getMusicFilename(String mediaId) {
+        return musicFileName.containsKey(mediaId) ? musicFileName.get(mediaId) : null;
+    }
+
+    private static int getAlbumRes(String mediaId) {
+        return albumRes.containsKey(mediaId) ? albumRes.get(mediaId) : 0;
+    }
+
+    public static Bitmap getAlbumBitmap(Context context, String mediaId) {
+        return BitmapFactory.decodeResource(context.getResources(),
+                MusicLibrary.getAlbumRes(mediaId));
+    }
+
+    public static List<MediaBrowserCompat.MediaItem> getMediaItems() {
+        List<MediaBrowserCompat.MediaItem> result = new ArrayList<>();
+        for (MediaMetadataCompat metadata : music.values()) {
+            result.add(
+                    new MediaBrowserCompat.MediaItem(
+                            metadata.getDescription(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE));
+        }
+        return result;
+    }
+
+    public static MediaMetadataCompat getMetadata(Context context, String mediaId) {
+        MediaMetadataCompat metadataWithoutBitmap = music.get(mediaId);
+        Bitmap albumArt = getAlbumBitmap(context, mediaId);
+
+        // Since MediaMetadataCompat is immutable, we need to create a copy to set the album art.
+        // We don't set it initially on all items so that they don't take unnecessary memory.
+        MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
+        for (String key :
+                new String[]{
+                        MediaMetadataCompat.METADATA_KEY_MEDIA_ID,
+                        MediaMetadataCompat.METADATA_KEY_ALBUM,
+                        MediaMetadataCompat.METADATA_KEY_ARTIST,
+                        MediaMetadataCompat.METADATA_KEY_GENRE,
+                        MediaMetadataCompat.METADATA_KEY_TITLE
+                }) {
+            builder.putString(key, metadataWithoutBitmap.getString(key));
+        }
+        builder.putLong(
+                MediaMetadataCompat.METADATA_KEY_DURATION,
+                metadataWithoutBitmap.getLong(MediaMetadataCompat.METADATA_KEY_DURATION));
+        builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt);
+        return builder.build();
+    }
+
+    private static void createMediaMetadataCompat(
+            String mediaId,
+            String title,
+            String artist,
+            String album,
+            String genre,
+            long duration,
+            TimeUnit durationUnit,
+            String musicFilename,
+            int albumArtResId,
+            String albumArtResName) {
+        music.put(
+                mediaId,
+                new MediaMetadataCompat.Builder()
+                        .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, mediaId)
+                        .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, album)
+                        .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
+                        .putLong(MediaMetadataCompat.METADATA_KEY_DURATION,
+                                 TimeUnit.MILLISECONDS.convert(duration, durationUnit))
+                        .putString(MediaMetadataCompat.METADATA_KEY_GENRE, genre)
+                        .putString(
+                                MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI,
+                                getAlbumArtUri(albumArtResName))
+                        .putString(
+                                MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI,
+                                getAlbumArtUri(albumArtResName))
+                        .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
+                        .build());
+        albumRes.put(mediaId, albumArtResId);
+        musicFileName.put(mediaId, musicFilename);
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/notifications/MediaNotificationManager.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/notifications/MediaNotificationManager.java
new file mode 100644
index 0000000..0274494
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/notifications/MediaNotificationManager.java
@@ -0,0 +1,214 @@
+/*
+ * 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.mediasession.service.notifications;
+
+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.Color;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.media.MediaDescriptionCompat;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.app.NotificationCompat.MediaStyle;
+import android.support.v4.media.session.MediaButtonReceiver;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
+import android.support.v4.os.BuildCompat;
+import android.util.Log;
+
+import com.example.android.mediasession.R;
+import com.example.android.mediasession.service.MusicService;
+import com.example.android.mediasession.service.PlaybackInfoListener;
+import com.example.android.mediasession.service.contentcatalogs.MusicLibrary;
+import com.example.android.mediasession.ui.MainActivity;
+
+
+/**
+ * Keeps track of a notification and updates it automatically for a given MediaSession. This is
+ * required so that the music service don't get killed during playback.
+ */
+public class MediaNotificationManager {
+
+    public static final int NOTIFICATION_ID = 412;
+
+    private static final String TAG = MediaNotificationManager.class.getSimpleName();
+    private static final String CHANNEL_ID = "com.example.android.musicplayer.channel";
+    private static final int REQUEST_CODE = 501;
+
+    private final MusicService mService;
+
+    private final NotificationCompat.Action mPlayAction;
+    private final NotificationCompat.Action mPauseAction;
+    private final NotificationCompat.Action mNextAction;
+    private final NotificationCompat.Action mPrevAction;
+    private final NotificationManager mNotificationManager;
+
+    public MediaNotificationManager(MusicService service) {
+        mService = service;
+
+        mNotificationManager =
+                (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);
+
+        mPlayAction =
+                new NotificationCompat.Action(
+                        R.drawable.ic_play_arrow_white_24dp,
+                        mService.getString(R.string.label_play),
+                        MediaButtonReceiver.buildMediaButtonPendingIntent(
+                                mService,
+                                PlaybackStateCompat.ACTION_PLAY));
+        mPauseAction =
+                new NotificationCompat.Action(
+                        R.drawable.ic_pause_white_24dp,
+                        mService.getString(R.string.label_pause),
+                        MediaButtonReceiver.buildMediaButtonPendingIntent(
+                                mService,
+                                PlaybackStateCompat.ACTION_PAUSE));
+        mNextAction =
+                new NotificationCompat.Action(
+                        R.drawable.ic_skip_next_white_24dp,
+                        mService.getString(R.string.label_next),
+                        MediaButtonReceiver.buildMediaButtonPendingIntent(
+                                mService,
+                                PlaybackStateCompat.ACTION_SKIP_TO_NEXT));
+        mPrevAction =
+                new NotificationCompat.Action(
+                        R.drawable.ic_skip_previous_white_24dp,
+                        mService.getString(R.string.label_previous),
+                        MediaButtonReceiver.buildMediaButtonPendingIntent(
+                                mService,
+                                PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS));
+
+        // Cancel all notifications to handle the case where the Service was killed and
+        // restarted by the system.
+        mNotificationManager.cancelAll();
+    }
+
+    public void onDestroy() {
+        Log.d(TAG, "onDestroy: ");
+    }
+
+    public NotificationManager getNotificationManager() {
+        return mNotificationManager;
+    }
+
+    public Notification getNotification(MediaMetadataCompat metadata,
+                                        @NonNull PlaybackStateCompat state,
+                                        MediaSessionCompat.Token token) {
+        boolean isPlaying = state.getState() == PlaybackStateCompat.STATE_PLAYING;
+        MediaDescriptionCompat description = metadata.getDescription();
+        NotificationCompat.Builder builder =
+                buildNotification(state, token, isPlaying, description);
+        return builder.build();
+    }
+
+    private NotificationCompat.Builder buildNotification(@NonNull PlaybackStateCompat state,
+                                                         MediaSessionCompat.Token token,
+                                                         boolean isPlaying,
+                                                         MediaDescriptionCompat description) {
+
+        // Create the (mandatory) notification channel when running on Android Oreo.
+        if (isAndroidOOrHigher()) {
+            createChannel();
+        }
+
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(mService, CHANNEL_ID);
+        builder.setStyle(
+                new MediaStyle()
+                        .setMediaSession(token)
+                        .setShowActionsInCompactView(0, 1, 2)
+                        // For backwards compatibility with Android L and earlier.
+                        .setShowCancelButton(true)
+                        .setCancelButtonIntent(
+                                MediaButtonReceiver.buildMediaButtonPendingIntent(
+                                        mService,
+                                        PlaybackStateCompat.ACTION_STOP)))
+                .setColor(ContextCompat.getColor(mService, R.color.notification_bg))
+                .setSmallIcon(R.drawable.ic_stat_image_audiotrack)
+                // Pending intent that is fired when user clicks on notification.
+                .setContentIntent(createContentIntent())
+                // Title - Usually Song name.
+                .setContentTitle(description.getTitle())
+                // Subtitle - Usually Artist name.
+                .setContentText(description.getSubtitle())
+                .setLargeIcon(MusicLibrary.getAlbumBitmap(mService, description.getMediaId()))
+                // When notification is deleted (when playback is paused and notification can be
+                // deleted) fire MediaButtonPendingIntent with ACTION_STOP.
+                .setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(
+                        mService, PlaybackStateCompat.ACTION_STOP))
+                // Show controls on lock screen even when user hides sensitive content.
+                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
+
+        // If skip to next action is enabled.
+        if ((state.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) != 0) {
+            builder.addAction(mPrevAction);
+        }
+
+        builder.addAction(isPlaying ? mPauseAction : mPlayAction);
+
+        // If skip to prev action is enabled.
+        if ((state.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0) {
+            builder.addAction(mNextAction);
+        }
+
+        return builder;
+    }
+
+    // Does nothing on versions of Android earlier than O.
+    @RequiresApi(Build.VERSION_CODES.O)
+    private void createChannel() {
+        if (mNotificationManager.getNotificationChannel(CHANNEL_ID) == null) {
+            // The user-visible name of the channel.
+            CharSequence name = "MediaSession";
+            // The user-visible description of the channel.
+            String description = "MediaSession and MediaPlayer";
+            int importance = NotificationManager.IMPORTANCE_LOW;
+            NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
+            // Configure the notification channel.
+            mChannel.setDescription(description);
+            mChannel.enableLights(true);
+            // Sets the notification light color for notifications posted to this
+            // channel, if the device supports this feature.
+            mChannel.setLightColor(Color.RED);
+            mChannel.enableVibration(true);
+            mChannel.setVibrationPattern(
+                    new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
+            mNotificationManager.createNotificationChannel(mChannel);
+            Log.d(TAG, "createChannel: New channel created");
+        } else {
+            Log.d(TAG, "createChannel: Existing channel reused");
+        }
+    }
+
+    private boolean isAndroidOOrHigher() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+    }
+
+    private PendingIntent createContentIntent() {
+        Intent openUI = new Intent(mService, MainActivity.class);
+        openUI.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+        return PendingIntent.getActivity(
+                mService, REQUEST_CODE, openUI, PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/players/MediaPlayerAdapter.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/players/MediaPlayerAdapter.java
new file mode 100644
index 0000000..d24f44f
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/service/players/MediaPlayerAdapter.java
@@ -0,0 +1,257 @@
+/*
+ * 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.mediasession.service.players;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.MediaPlayer;
+import android.os.SystemClock;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
+import android.util.Log;
+
+import com.example.android.mediasession.service.PlaybackInfoListener;
+import com.example.android.mediasession.service.PlayerAdapter;
+import com.example.android.mediasession.service.contentcatalogs.MusicLibrary;
+import com.example.android.mediasession.ui.MainActivity;
+
+/**
+ * Exposes the functionality of the {@link MediaPlayer} and implements the {@link PlayerAdapter}
+ * so that {@link MainActivity} can control music playback.
+ */
+public final class MediaPlayerAdapter extends PlayerAdapter {
+
+    private final Context mContext;
+    private MediaPlayer mMediaPlayer;
+    private String mFilename;
+    private PlaybackInfoListener mPlaybackInfoListener;
+    private MediaMetadataCompat mCurrentMedia;
+    private int mState;
+    private boolean mCurrentMediaPlayedToCompletion;
+
+    // Work-around for a MediaPlayer bug related to the behavior of MediaPlayer.seekTo()
+    // while not playing.
+    private int mSeekWhileNotPlaying = -1;
+
+    public MediaPlayerAdapter(Context context, PlaybackInfoListener listener) {
+        super(context);
+        mContext = context.getApplicationContext();
+        mPlaybackInfoListener = listener;
+    }
+
+    /**
+     * Once the {@link MediaPlayer} is released, it can't be used again, and another one has to be
+     * created. In the onStop() method of the {@link MainActivity} the {@link MediaPlayer} is
+     * released. Then in the onStart() of the {@link MainActivity} a new {@link MediaPlayer}
+     * object has to be created. That's why this method is private, and called by load(int) and
+     * not the constructor.
+     */
+    private void initializeMediaPlayer() {
+        if (mMediaPlayer == null) {
+            mMediaPlayer = new MediaPlayer();
+            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+                @Override
+                public void onCompletion(MediaPlayer mediaPlayer) {
+                    mPlaybackInfoListener.onPlaybackCompleted();
+
+                    // Set the state to "paused" because it most closely matches the state
+                    // in MediaPlayer with regards to available state transitions compared
+                    // to "stop".
+                    // Paused allows: seekTo(), start(), pause(), stop()
+                    // Stop allows: stop()
+                    setNewState(PlaybackStateCompat.STATE_PAUSED);
+                }
+            });
+        }
+    }
+
+    // Implements PlaybackControl.
+    @Override
+    public void playFromMedia(MediaMetadataCompat metadata) {
+        mCurrentMedia = metadata;
+        final String mediaId = metadata.getDescription().getMediaId();
+        playFile(MusicLibrary.getMusicFilename(mediaId));
+    }
+
+    @Override
+    public MediaMetadataCompat getCurrentMedia() {
+        return mCurrentMedia;
+    }
+
+    private void playFile(String filename) {
+        boolean mediaChanged = (mFilename == null || !filename.equals(mFilename));
+        if (mCurrentMediaPlayedToCompletion) {
+            // Last audio file was played to completion, the resourceId hasn't changed, but the
+            // player was released, so force a reload of the media file for playback.
+            mediaChanged = true;
+            mCurrentMediaPlayedToCompletion = false;
+        }
+        if (!mediaChanged) {
+            if (!isPlaying()) {
+                play();
+            }
+            return;
+        } else {
+            release();
+        }
+
+        mFilename = filename;
+
+        initializeMediaPlayer();
+
+        try {
+            AssetFileDescriptor assetFileDescriptor = mContext.getAssets().openFd(mFilename);
+            mMediaPlayer.setDataSource(
+                    assetFileDescriptor.getFileDescriptor(),
+                    assetFileDescriptor.getStartOffset(),
+                    assetFileDescriptor.getLength());
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to open file: " + mFilename, e);
+        }
+
+        try {
+            mMediaPlayer.prepare();
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to open file: " + mFilename, e);
+        }
+
+        play();
+    }
+
+    @Override
+    public void onStop() {
+        // Regardless of whether or not the MediaPlayer has been created / started, the state must
+        // be updated, so that MediaNotificationManager can take down the notification.
+        setNewState(PlaybackStateCompat.STATE_STOPPED);
+        release();
+    }
+
+    private void release() {
+        if (mMediaPlayer != null) {
+            mMediaPlayer.release();
+            mMediaPlayer = null;
+        }
+    }
+
+    @Override
+    public boolean isPlaying() {
+        return mMediaPlayer != null && mMediaPlayer.isPlaying();
+    }
+
+    @Override
+    protected void onPlay() {
+        if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
+            mMediaPlayer.start();
+            setNewState(PlaybackStateCompat.STATE_PLAYING);
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
+            mMediaPlayer.pause();
+            setNewState(PlaybackStateCompat.STATE_PAUSED);
+        }
+    }
+
+    // This is the main reducer for the player state machine.
+    private void setNewState(@PlaybackStateCompat.State int newPlayerState) {
+        mState = newPlayerState;
+
+        // Whether playback goes to completion, or whether it is stopped, the
+        // mCurrentMediaPlayedToCompletion is set to true.
+        if (mState == PlaybackStateCompat.STATE_STOPPED) {
+            mCurrentMediaPlayedToCompletion = true;
+        }
+
+        // Work around for MediaPlayer.getCurrentPosition() when it changes while not playing.
+        final long reportPosition;
+        if (mSeekWhileNotPlaying >= 0) {
+            reportPosition = mSeekWhileNotPlaying;
+
+            if (mState == PlaybackStateCompat.STATE_PLAYING) {
+                mSeekWhileNotPlaying = -1;
+            }
+        } else {
+            reportPosition = mMediaPlayer == null ? 0 : mMediaPlayer.getCurrentPosition();
+        }
+
+        final PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder();
+        stateBuilder.setActions(getAvailableActions());
+        stateBuilder.setState(mState,
+                              reportPosition,
+                              1.0f,
+                              SystemClock.elapsedRealtime());
+        mPlaybackInfoListener.onPlaybackStateChange(stateBuilder.build());
+    }
+
+    /**
+     * Set the current capabilities available on this session. Note: If a capability is not
+     * listed in the bitmask of capabilities then the MediaSession will not handle it. For
+     * example, if you don't want ACTION_STOP to be handled by the MediaSession, then don't
+     * included it in the bitmask that's returned.
+     */
+    @PlaybackStateCompat.Actions
+    private long getAvailableActions() {
+        long actions = PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID
+                       | PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH
+                       | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
+                       | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
+        switch (mState) {
+            case PlaybackStateCompat.STATE_STOPPED:
+                actions |= PlaybackStateCompat.ACTION_PLAY
+                           | PlaybackStateCompat.ACTION_PAUSE;
+                break;
+            case PlaybackStateCompat.STATE_PLAYING:
+                actions |= PlaybackStateCompat.ACTION_STOP
+                           | PlaybackStateCompat.ACTION_PAUSE
+                           | PlaybackStateCompat.ACTION_SEEK_TO;
+                break;
+            case PlaybackStateCompat.STATE_PAUSED:
+                actions |= PlaybackStateCompat.ACTION_PLAY
+                           | PlaybackStateCompat.ACTION_STOP;
+                break;
+            default:
+                actions |= PlaybackStateCompat.ACTION_PLAY
+                           | PlaybackStateCompat.ACTION_PLAY_PAUSE
+                           | PlaybackStateCompat.ACTION_STOP
+                           | PlaybackStateCompat.ACTION_PAUSE;
+        }
+        return actions;
+    }
+
+    @Override
+    public void seekTo(long position) {
+        if (mMediaPlayer != null) {
+            if (!mMediaPlayer.isPlaying()) {
+                mSeekWhileNotPlaying = (int) position;
+            }
+            mMediaPlayer.seekTo((int) position);
+
+            // Set the state (to the current state) because the position changed and should
+            // be reported to clients.
+            setNewState(mState);
+        }
+    }
+
+    @Override
+    public void setVolume(float volume) {
+        if (mMediaPlayer != null) {
+            mMediaPlayer.setVolume(volume, volume);
+        }
+    }
+}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/ui/MainActivity.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/ui/MainActivity.java
new file mode 100644
index 0000000..4991789
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/ui/MainActivity.java
@@ -0,0 +1,133 @@
+/*
+ * 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.mediasession.ui;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.example.android.mediasession.R;
+import com.example.android.mediasession.client.MediaBrowserAdapter;
+import com.example.android.mediasession.service.contentcatalogs.MusicLibrary;
+
+public class MainActivity extends AppCompatActivity {
+
+    private ImageView mAlbumArt;
+    private TextView mTitleTextView;
+    private TextView mArtistTextView;
+    private ImageView mMediaControlsImage;
+    private MediaSeekBar mSeekBarAudio;
+
+    private MediaBrowserAdapter mMediaBrowserAdapter;
+
+    private boolean mIsPlaying;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        initializeUI();
+        mMediaBrowserAdapter = new MediaBrowserAdapter(this);
+        mMediaBrowserAdapter.addListener(new MediaBrowserListener());
+    }
+
+    private void initializeUI() {
+        mTitleTextView = (TextView) findViewById(R.id.song_title);
+        mArtistTextView = (TextView) findViewById(R.id.song_artist);
+        mAlbumArt = (ImageView) findViewById(R.id.album_art);
+        mMediaControlsImage = (ImageView) findViewById(R.id.media_controls);
+        mSeekBarAudio = (MediaSeekBar) findViewById(R.id.seekbar_audio);
+
+        final Button buttonPrevious = (Button) findViewById(R.id.button_previous);
+        buttonPrevious.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mMediaBrowserAdapter.getTransportControls().skipToPrevious();
+            }
+        });
+
+        final Button buttonPlay = (Button) findViewById(R.id.button_play);
+        buttonPlay.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mIsPlaying) {
+                    mMediaBrowserAdapter.getTransportControls().pause();
+                } else {
+                    mMediaBrowserAdapter.getTransportControls().play();
+                }
+            }
+        });
+
+        final Button buttonNext = (Button) findViewById(R.id.button_next);
+        buttonNext.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mMediaBrowserAdapter.getTransportControls().skipToNext();
+            }
+        });
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mMediaBrowserAdapter.onStart();
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        mSeekBarAudio.disconnectController();
+        mMediaBrowserAdapter.onStop();
+    }
+
+    private class MediaBrowserListener extends MediaBrowserAdapter.MediaBrowserChangeListener {
+
+        @Override
+        public void onConnected(@Nullable MediaControllerCompat mediaController) {
+            super.onConnected(mediaController);
+            mSeekBarAudio.setMediaController(mediaController);
+        }
+
+        @Override
+        public void onPlaybackStateChanged(PlaybackStateCompat playbackState) {
+            mIsPlaying = playbackState != null &&
+                    playbackState.getState() == PlaybackStateCompat.STATE_PLAYING;
+            mMediaControlsImage.setPressed(mIsPlaying);
+        }
+
+        @Override
+        public void onMetadataChanged(MediaMetadataCompat mediaMetadata) {
+            if (mediaMetadata == null) {
+                return;
+            }
+            mTitleTextView.setText(
+                    mediaMetadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE));
+            mArtistTextView.setText(
+                    mediaMetadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST));
+            mAlbumArt.setImageBitmap(MusicLibrary.getAlbumBitmap(
+                    MainActivity.this,
+                    mediaMetadata.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID)));
+        }
+    }
+}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/ui/MediaSeekBar.java b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/ui/MediaSeekBar.java
new file mode 100644
index 0000000..71de9ca
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/java/com/example/android/mediasession/ui/MediaSeekBar.java
@@ -0,0 +1,158 @@
+/*
+ * 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.mediasession.ui;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+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;
+import android.support.v7.widget.AppCompatSeekBar;
+import android.util.AttributeSet;
+import android.view.animation.LinearInterpolator;
+import android.widget.SeekBar;
+
+/**
+ * SeekBar that can be used with a {@link MediaSessionCompat} to track and seek in playing
+ * media.
+ */
+
+public class MediaSeekBar extends AppCompatSeekBar {
+    private MediaControllerCompat mMediaController;
+    private ControllerCallback mControllerCallback;
+
+    private boolean mIsTracking = false;
+    private OnSeekBarChangeListener mOnSeekBarChangeListener = new OnSeekBarChangeListener() {
+        @Override
+        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+        }
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+            mIsTracking = true;
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            mMediaController.getTransportControls().seekTo(getProgress());
+            mIsTracking = false;
+        }
+    };
+    private ValueAnimator mProgressAnimator;
+
+    public MediaSeekBar(Context context) {
+        super(context);
+        super.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
+    }
+
+    public MediaSeekBar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        super.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
+    }
+
+    public MediaSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        super.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
+    }
+
+    @Override
+    public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
+        // Prohibit adding seek listeners to this subclass.
+    }
+
+    public void setMediaController(final MediaControllerCompat mediaController) {
+        if (mediaController != null) {
+            mControllerCallback = new ControllerCallback();
+            mediaController.registerCallback(mControllerCallback);
+        } else if (mMediaController != null) {
+            mMediaController.unregisterCallback(mControllerCallback);
+            mControllerCallback = null;
+        }
+        mMediaController = mediaController;
+    }
+
+    public void disconnectController() {
+        if (mMediaController != null) {
+            mMediaController.unregisterCallback(mControllerCallback);
+            mControllerCallback = null;
+            mMediaController = null;
+        }
+    }
+
+    private class ControllerCallback
+            extends MediaControllerCompat.Callback
+            implements ValueAnimator.AnimatorUpdateListener {
+
+        @Override
+        public void onSessionDestroyed() {
+            super.onSessionDestroyed();
+        }
+
+        @Override
+        public void onPlaybackStateChanged(PlaybackStateCompat state) {
+            super.onPlaybackStateChanged(state);
+
+            // If there's an ongoing animation, stop it now.
+            if (mProgressAnimator != null) {
+                mProgressAnimator.cancel();
+                mProgressAnimator = null;
+            }
+
+            final int progress = state != null
+                    ? (int) state.getPosition()
+                    : 0;
+            setProgress(progress);
+
+            // If the media is playing then the seekbar should follow it, and the easiest
+            // way to do that is to create a ValueAnimator to update it so the bar reaches
+            // the end of the media the same time as playback gets there (or close enough).
+            if (state != null && state.getState() == PlaybackStateCompat.STATE_PLAYING) {
+                final int timeToEnd = (int) ((getMax() - progress) / state.getPlaybackSpeed());
+
+                mProgressAnimator = ValueAnimator.ofInt(progress, getMax())
+                        .setDuration(timeToEnd);
+                mProgressAnimator.setInterpolator(new LinearInterpolator());
+                mProgressAnimator.addUpdateListener(this);
+                mProgressAnimator.start();
+            }
+        }
+
+        @Override
+        public void onMetadataChanged(MediaMetadataCompat metadata) {
+            super.onMetadataChanged(metadata);
+
+            final int max = metadata != null
+                    ? (int) metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION)
+                    : 0;
+            setProgress(0);
+            setMax(max);
+        }
+
+        @Override
+        public void onAnimationUpdate(final ValueAnimator valueAnimator) {
+            // If the user is changing the slider, cancel the animation.
+            if (mIsTracking) {
+                valueAnimator.cancel();
+                return;
+            }
+
+            final int animatedIntValue = (int) valueAnimator.getAnimatedValue();
+            setProgress(animatedIntValue);
+        }
+    }
+}
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 05ef6f6..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_notification.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_notification.png
deleted file mode 100644
index a8cba40..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_notification.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_pause_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_pause_white_24dp.png
index b4bdbb5..f7b3c1e 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_pause_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
index 164385d..be73548 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png
deleted file mode 100644
index 3eeb0ef..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png
index 4eaf7ca..3c6ae11 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png
index e59dedb..6883e61 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_stat_image_audiotrack.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_stat_image_audiotrack.png
new file mode 100755
index 0000000..bbbaa0e
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_stat_image_audiotrack.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index f894fb8..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_pause_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_pause_white_24dp.png
new file mode 100644
index 0000000..499341f
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 0000000..bebdf37
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_skip_next_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_skip_next_white_24dp.png
new file mode 100644
index 0000000..d55f7e6
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_skip_previous_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_skip_previous_white_24dp.png
new file mode 100644
index 0000000..259797d
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_stat_image_audiotrack.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_stat_image_audiotrack.png
new file mode 100755
index 0000000..e445a0c
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_stat_image_audiotrack.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-nodpi/album_jazz_blues.jpg b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-nodpi/album_jazz_blues.jpg
new file mode 100644
index 0000000..d3ffefc
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-nodpi/album_jazz_blues.jpg
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-nodpi/album_youtube_audio_library_rock_2.jpg b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-nodpi/album_youtube_audio_library_rock_2.jpg
new file mode 100644
index 0000000..8d5020c
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-nodpi/album_youtube_audio_library_rock_2.jpg
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_equalizer_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_equalizer_white_24dp.png
deleted file mode 100644
index dbba844..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_equalizer_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 43ade5e..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png
index 14b6d17..e31b5b0 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
index a55d199..929ffec 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png
deleted file mode 100644
index 8ce3a60..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png
index f282b92..343b7bb 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png
index 2522877..e926c5e 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_stat_image_audiotrack.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_stat_image_audiotrack.png
new file mode 100755
index 0000000..5481659
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_stat_image_audiotrack.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_by_genre.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_by_genre.png
deleted file mode 100644
index da3b4a7..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_by_genre.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_default_art.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_default_art.png
deleted file mode 100644
index dfb9e67..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_default_art.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_equalizer_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_equalizer_white_24dp.png
deleted file mode 100644
index b82a8d9..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_equalizer_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 3058c27..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_media_with_pause.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_media_with_pause.png
new file mode 100644
index 0000000..c6041da
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_media_with_pause.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_media_with_play.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_media_with_play.png
new file mode 100644
index 0000000..a0da57b
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_media_with_play.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png
index 72dfa9f..1e71ba3 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
index 043acd8..4abfe88 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png
deleted file mode 100644
index 718b6b5..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png
index 4fe6088..616e47f 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png
index 2c9310a..1ec9d65 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_off.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_off.png
deleted file mode 100644
index fb7afb0..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_off.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_on.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_on.png
deleted file mode 100644
index 6f7fc75..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_on.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_stat_image_audiotrack.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_stat_image_audiotrack.png
new file mode 100755
index 0000000..f214042
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_stat_image_audiotrack.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 6b4e4a2..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable/ic_play_pause_toggle.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable/ic_play_pause_toggle.xml
new file mode 100644
index 0000000..2fe59d9
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/drawable/ic_play_pause_toggle.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/ic_media_with_play" android:state_pressed="false" />
+    <item android:drawable="@drawable/ic_media_with_pause" />
+</selector>
\ No newline at end of file
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/activity_main.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..76b8699
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/activity_main.xml
@@ -0,0 +1,133 @@
+<?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.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/frameLayout"
+                                             android:layout_width="match_parent"
+                                             android:layout_height="match_parent"
+                                             tools:background="@drawable/album_jazz_blues">
+
+    <ImageView
+        android:id="@+id/album_art"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="fitXY"
+        tools:ignore="ContentDescription" />
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:background="#a0ffffff"
+        app:layout_constraintBottom_toBottomOf="@+id/song_artist"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:ignore="ContentDescription" />
+
+    <TextView
+        android:id="@+id/song_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="0dp"
+        android:gravity="center"
+        android:textAppearance="@style/TextAppearance.AppCompat.Large"
+        app:layout_constraintBottom_toBottomOf="@+id/song_artist"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="Song Title" />
+
+    <TextView
+        android:id="@+id/song_artist"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:paddingBottom="12dp"
+        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/song_title"
+        tools:text="Song Artist" />
+
+    <ImageView
+        android:id="@+id/media_controls"
+        android:layout_width="192dp"
+        android:layout_height="192dp"
+        android:alpha=".9"
+        android:src="@drawable/ic_play_pause_toggle"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/guideline"
+        tools:ignore="ContentDescription" />
+
+    <Button
+        android:id="@+id/button_previous"
+        android:layout_width="50dp"
+        android:layout_height="0dp"
+        android:background="@android:color/transparent"
+        android:contentDescription="@string/label_previous"
+        android:text=""
+        app:layout_constraintBottom_toBottomOf="@+id/media_controls"
+        app:layout_constraintStart_toStartOf="@+id/media_controls"
+        app:layout_constraintTop_toTopOf="@+id/media_controls" />
+
+    <Button
+        android:id="@+id/button_play"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:background="@android:color/transparent"
+        android:contentDescription="@string/label_play_pause"
+        android:text=""
+        app:layout_constraintBottom_toBottomOf="@+id/media_controls"
+        app:layout_constraintEnd_toStartOf="@+id/button_next"
+        app:layout_constraintStart_toEndOf="@+id/button_previous"
+        app:layout_constraintTop_toTopOf="@+id/media_controls" />
+
+    <Button
+        android:id="@+id/button_next"
+        android:layout_width="50dp"
+        android:layout_height="0dp"
+        android:layout_marginStart="8dp"
+        android:background="@android:color/transparent"
+        android:contentDescription="@string/label_next"
+        android:text=""
+        app:layout_constraintBottom_toBottomOf="@+id/media_controls"
+        app:layout_constraintEnd_toEndOf="@+id/media_controls"
+        app:layout_constraintTop_toTopOf="@+id/media_controls" />
+
+    <android.support.constraint.Guideline
+        android:id="@+id/guideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_percent=".5" />
+
+    <com.example.android.mediasession.ui.MediaSeekBar
+        android:id="@+id/seekbar_audio"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="16dp"
+        android:layout_marginStart="16dp"
+        android:paddingBottom="16dp"
+        android:paddingTop="16dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/activity_player.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/activity_player.xml
deleted file mode 100644
index 64b47ee..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/activity_player.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-  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.
-  -->
-<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=".MusicPlayerActivity"
-             tools:ignore="MergeRootFrame"/>
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/fragment_list.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/fragment_list.xml
deleted file mode 100644
index 8c5985b..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/fragment_list.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
-  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.
-  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:background="?android:colorBackground"
-              android:orientation="vertical"
-              android:padding="@dimen/fragment_list_padding">
-
-    <ListView
-        android:id="@+id/list_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    </ListView>
-
-</LinearLayout>
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/media_list_item.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/media_list_item.xml
deleted file mode 100644
index c10ac51..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/layout/media_list_item.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<!--
-  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.
-  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:minHeight="?android:listPreferredItemHeight"
-              android:orientation="horizontal">
-
-    <ImageView
-        android:id="@+id/play_eq"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:contentDescription="@string/play_item"
-        android:src="@drawable/ic_play_arrow_white_24dp"/>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="?android:attr/listPreferredItemHeight"
-        android:mode="twoLine"
-        android:orientation="vertical"
-        android:padding="@dimen/list_item_padding">
-
-        <TextView
-            android:id="@+id/title"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="@dimen/margin_text_view"
-            android:layout_marginTop="@dimen/margin_text_view"
-            android:textAppearance="?android:attr/textAppearanceMedium"/>
-
-        <TextView
-            android:id="@+id/description"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="@dimen/margin_text_view"
-            android:layout_marginTop="@dimen/margin_text_view"
-            android:textAppearance="?android:attr/textAppearanceSmall"/>
-
-    </LinearLayout>
-
-</LinearLayout>
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-hdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100755
index 0000000..1d1b1a0
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-mdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100755
index 0000000..11570be
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-xhdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..dc44e16
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..5826256
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100755
index 0000000..b226a47
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/colors.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..323a89b
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/colors.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>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+    <color name="notification_bg">#e91e63</color>
+</resources>
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/dimens.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/dimens.xml
deleted file mode 100644
index e57a8c9..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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.
-  -->
-<resources>
-    <dimen name="fragment_list_padding">16dp</dimen>
-    <dimen name="list_item_padding">4dp</dimen>
-    <dimen name="margin_text_view">6dp</dimen>
-</resources>
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/strings.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/strings.xml
index 9a4a50a..93b3eac 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/strings.xml
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/strings.xml
@@ -1,34 +1,25 @@
-<?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.
+  ~ 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">MediaBrowserService Sample</string>
-    <string name="favorite">Favorite</string>
-    <string name="error_no_metadata">Unable to retrieve metadata.</string>
-    <string name="browse_genres">Genres</string>
-    <string name="browse_genre_subtitle">Songs by genre</string>
-    <string name="browse_musics_by_genre_subtitle">%1$s songs</string>
-    <string name="random_queue_title">Random music</string>
-    <string name="error_cannot_skip">Cannot skip</string>
-    <string name="error_loading_media">Error Loading Media</string>
-    <string name="play_item">Play item</string>
-    <string name="skip_previous">Skip to previous</string>
-    <string name="play_pause">play or pause</string>
-    <string name="skip_next">Skip to next</string>
-    <string name="no_search_results">No search results.</string>
-
+    <string name="label_stop">Stop</string>
+    <string name="label_pause">Pause</string>
+    <string name="label_play">Play</string>
+    <string name="label_play_pause">Play and pause toggle</string>
+    <string name="label_previous">Previous track</string>
+    <string name="label_next">Next track</string>
 </resources>
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/strings_notifications.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/strings_notifications.xml
deleted file mode 100644
index 7e1ccd5..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/strings_notifications.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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.
-  -->
-<resources>
-
-    <string name="label_pause">Pause</string>
-    <string name="label_play">Play</string>
-    <string name="label_previous">Previous</string>
-    <string name="label_next">Next</string>
-
-</resources>
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/styles.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/styles.xml
index 5d91ab4..69ee900 100644
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/styles.xml
+++ b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/values/styles.xml
@@ -1,45 +1,27 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2014 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.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
 
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES 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">#ffff5722</color>
-    <color name="colorPrimaryDark">#ffbf360c</color>
-    <color name="colorAccent">#ffff5722</color>
 
-    <style name="AppTheme" parent="Theme.AppCompat">
+    <!-- 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="CarTheme" parent="AppTheme">
-        <!-- colorPrimaryDark is currently used in Android Auto for:
-             - App background
-             - Drawer right side ("more" custom actions) background
-             - Notification icon badge tinting
-             - Overview “now playing” icon tinting
-         -->
-        <item name="colorPrimaryDark">#ffbf360c</item>
-
-        <!-- colorAccent is used in Android Auto for:
-             - Spinner
-             - progress bar
-             - floating action button background (Play/Pause in media apps)
-         -->
-        <item name="colorAccent">#ffff5722</item>
-    </style>
-
-</resources>
\ No newline at end of file
+</resources>
diff --git a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/xml/automotive_app_desc.xml b/prebuilts/gradle/MediaBrowserService/Application/src/main/res/xml/automotive_app_desc.xml
deleted file mode 100644
index a84750b..0000000
--- a/prebuilts/gradle/MediaBrowserService/Application/src/main/res/xml/automotive_app_desc.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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.
-  -->
-<automotiveApp>
-    <uses name="media"/>
-</automotiveApp>
diff --git a/prebuilts/gradle/MediaBrowserService/CONTRIB.md b/prebuilts/gradle/MediaBrowserService/CONTRIB.md
deleted file mode 100644
index 14a4fcf..0000000
--- a/prebuilts/gradle/MediaBrowserService/CONTRIB.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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/prebuilts/gradle/MediaBrowserService/README.md b/prebuilts/gradle/MediaBrowserService/README.md
index 3059c5b..2deee4e 100644
--- a/prebuilts/gradle/MediaBrowserService/README.md
+++ b/prebuilts/gradle/MediaBrowserService/README.md
@@ -2,16 +2,22 @@
 Android MediaBrowserService Sample
 ===================================
 
-This sample shows how to implement an audio media app that provides
-media library metadata and playback controls through a standard
-service. It exposes a simple music library through the new
-MediaBrowserService and provides MediaSession callbacks. This allows
-it to be used in Android Auto, for example.
-When not connected to a car, the app has a very simple UI that browses
-the media library and provides simple playback controls. When
-connected to Android Auto, the same service provides data and callback
-to the Android Auto UI in the same manner as it provides them to the
-local UI.
+This sample shows how to implement a media app that allows
+background playback of audio, and provide a media library
+that is exposed to other apps.
+1. It allows other apps control media playback externally
+using MediaSession. This allows playback to be controlled by
+the Google Assistant, for example.
+2. It exposes a simple music library through MediaBrowserService.
+And it provides MediaSession callbacks. This allows it to be used
+by Android Auto, for example.
+When not connected to a car, the app has a very simple UI that
+allows for playback as well as skip to previous and next tracks.
+To learn more about MediaSession and MediaBrowserService, read
+this [article on Medium](https://medium.com/google-developers/understanding-mediasession-part-4-4-dcc77c535f99)
+that goes into the architectural details of these APIs.
+
+<img src="screenshots/architecture.png" height="400" alt="Architecture Diagram"/>
 
 Introduction
 ------------
@@ -72,14 +78,14 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
 -------------
 
-<img src="screenshots/1-main.png" height="400" alt="Screenshot"/> <img src="screenshots/2-music-play.png" height="400" alt="Screenshot"/> <img src="screenshots/3-music-notification.png" height="400" alt="Screenshot"/> 
+<img src="screenshots/1-main.png" height="400" alt="Screenshot"/> <img src="screenshots/2-notification.png" height="400" alt="Screenshot"/> 
 
 Getting Started
 ---------------
diff --git a/prebuilts/gradle/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties
index fdc22bf..a93175f 100644
--- a/prebuilts/gradle/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties
+++ b/prebuilts/gradle/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Mar 22 15:15:46 PDT 2017
+#Tue Sep 19 11:11:29 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.1-all.zip
diff --git a/prebuilts/gradle/MediaBrowserService/packaging.yaml b/prebuilts/gradle/MediaBrowserService/packaging.yaml
index bcd9ac5..b1d7bbd 100644
--- a/prebuilts/gradle/MediaBrowserService/packaging.yaml
+++ b/prebuilts/gradle/MediaBrowserService/packaging.yaml
@@ -10,6 +10,6 @@
 languages:    [Java]
 solutions:    [Mobile]
 github:       googlesamples/android-MediaBrowserService
-level:        BEGINNER
-icon:         MediaBrowserServiceSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+level:        ADVANCED
+icon:         MediaBrowserServiceSample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
 license:      apache2-android
diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/1-main.png b/prebuilts/gradle/MediaBrowserService/screenshots/1-main.png
index 1b17d0e..f5e08a2 100644
--- a/prebuilts/gradle/MediaBrowserService/screenshots/1-main.png
+++ b/prebuilts/gradle/MediaBrowserService/screenshots/1-main.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/2-music-play.png b/prebuilts/gradle/MediaBrowserService/screenshots/2-music-play.png
deleted file mode 100644
index 1c1439c..0000000
--- a/prebuilts/gradle/MediaBrowserService/screenshots/2-music-play.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/2-notification.png b/prebuilts/gradle/MediaBrowserService/screenshots/2-notification.png
new file mode 100644
index 0000000..92ed70e
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/screenshots/2-notification.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/3-music-notification.png b/prebuilts/gradle/MediaBrowserService/screenshots/3-music-notification.png
deleted file mode 100644
index c86c045..0000000
--- a/prebuilts/gradle/MediaBrowserService/screenshots/3-music-notification.png
+++ /dev/null
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/architecture.png b/prebuilts/gradle/MediaBrowserService/screenshots/architecture.png
new file mode 100644
index 0000000..7cc48bc
--- /dev/null
+++ b/prebuilts/gradle/MediaBrowserService/screenshots/architecture.png
Binary files differ
diff --git a/prebuilts/gradle/MediaBrowserService/screenshots/icon-web.png b/prebuilts/gradle/MediaBrowserService/screenshots/icon-web.png
index 99928a8..df4c249 100644
--- a/prebuilts/gradle/MediaBrowserService/screenshots/icon-web.png
+++ b/prebuilts/gradle/MediaBrowserService/screenshots/icon-web.png
Binary files differ
diff --git a/prebuilts/gradle/MediaEffects/Application/build.gradle b/prebuilts/gradle/MediaEffects/Application/build.gradle
index e81066a..9267a5e 100644
--- a/prebuilts/gradle/MediaEffects/Application/build.gradle
+++ b/prebuilts/gradle/MediaEffects/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 14
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/MediaEffects/README.md b/prebuilts/gradle/MediaEffects/README.md
index 35284ae..d4ef9e1 100644
--- a/prebuilts/gradle/MediaEffects/README.md
+++ b/prebuilts/gradle/MediaEffects/README.md
@@ -21,8 +21,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/MediaRecorder/Application/build.gradle b/prebuilts/gradle/MediaRecorder/Application/build.gradle
index ddee143..7473a10 100644
--- a/prebuilts/gradle/MediaRecorder/Application/build.gradle
+++ b/prebuilts/gradle/MediaRecorder/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 16
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/MediaRecorder/README.md b/prebuilts/gradle/MediaRecorder/README.md
index bc197aa..b3e0ae0 100644
--- a/prebuilts/gradle/MediaRecorder/README.md
+++ b/prebuilts/gradle/MediaRecorder/README.md
@@ -25,8 +25,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/MediaRouter/Application/build.gradle b/prebuilts/gradle/MediaRouter/Application/build.gradle
index c391ee8..89878f1 100644
--- a/prebuilts/gradle/MediaRouter/Application/build.gradle
+++ b/prebuilts/gradle/MediaRouter/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.android.support:mediarouter-v7:24.2.1'
 }
 
@@ -32,12 +35,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 17
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/MediaRouter/Application/src/main/java/com/example/android/mediarouter/player/MainActivity.java b/prebuilts/gradle/MediaRouter/Application/src/main/java/com/example/android/mediarouter/player/MainActivity.java
index 8414ffb..2e61187 100644
--- a/prebuilts/gradle/MediaRouter/Application/src/main/java/com/example/android/mediarouter/player/MainActivity.java
+++ b/prebuilts/gradle/MediaRouter/Application/src/main/java/com/example/android/mediarouter/player/MainActivity.java
@@ -31,7 +31,7 @@
 import android.os.SystemClock;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.MediaRouteActionProvider;
 import android.support.v7.app.MediaRouteDiscoveryFragment;
 import android.support.v7.media.MediaControlIntent;
@@ -75,7 +75,7 @@
  * targets.
  * </p>
  */
-public class MainActivity extends ActionBarActivity {
+public class MainActivity extends AppCompatActivity {
     private static final String TAG = "MainActivity";
     private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment";
 
diff --git a/prebuilts/gradle/MediaRouter/README.md b/prebuilts/gradle/MediaRouter/README.md
index 554097e..5f4076b 100644
--- a/prebuilts/gradle/MediaRouter/README.md
+++ b/prebuilts/gradle/MediaRouter/README.md
@@ -7,8 +7,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/MessagingService/Application/build.gradle b/prebuilts/gradle/MessagingService/Application/build.gradle
index 67c5891..6c77afd 100644
--- a/prebuilts/gradle/MessagingService/Application/build.gradle
+++ b/prebuilts/gradle/MessagingService/Application/build.gradle
@@ -2,21 +2,30 @@
 buildscript {
     repositories {
         jcenter()
+        maven {
+            url 'https://maven.google.com'
+        }
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.1'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
 apply plugin: 'com.android.application'
 
+repositories {
+    jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
+}
 
 dependencies {
 
-    compile "com.android.support:support-v4:25.1.1"
-    compile "com.android.support:support-v13:25.1.1"
-    compile "com.android.support:cardview-v7:25.1.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
 
 }
 
@@ -29,8 +38,9 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 24
-    buildToolsVersion "25.0.3"
+        compileSdkVersion 24
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
diff --git a/prebuilts/gradle/MessagingService/README.md b/prebuilts/gradle/MessagingService/README.md
index f79c94e..232295c 100644
--- a/prebuilts/gradle/MessagingService/README.md
+++ b/prebuilts/gradle/MessagingService/README.md
@@ -51,7 +51,7 @@
 --------------
 
 - Android SDK 24
-- Android Build Tools v25.0.3
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/MidiScope/Application/build.gradle b/prebuilts/gradle/MidiScope/Application/build.gradle
index cdcf106..2ad233b 100644
--- a/prebuilts/gradle/MidiScope/Application/build.gradle
+++ b/prebuilts/gradle/MidiScope/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 23
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/MidiScope/README.md b/prebuilts/gradle/MidiScope/README.md
index 1cf3b55..3b77ccf 100644
--- a/prebuilts/gradle/MidiScope/README.md
+++ b/prebuilts/gradle/MidiScope/README.md
@@ -19,8 +19,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/MidiSynth/Application/build.gradle b/prebuilts/gradle/MidiSynth/Application/build.gradle
index cdcf106..2ad233b 100644
--- a/prebuilts/gradle/MidiSynth/Application/build.gradle
+++ b/prebuilts/gradle/MidiSynth/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 23
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/MidiSynth/README.md b/prebuilts/gradle/MidiSynth/README.md
index 192556f..85c8657 100644
--- a/prebuilts/gradle/MidiSynth/README.md
+++ b/prebuilts/gradle/MidiSynth/README.md
@@ -24,8 +24,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/MultiWindowPlayground/README.md b/prebuilts/gradle/MultiWindowPlayground/README.md
index 06040db..ac51761 100644
--- a/prebuilts/gradle/MultiWindowPlayground/README.md
+++ b/prebuilts/gradle/MultiWindowPlayground/README.md
@@ -49,7 +49,7 @@
 --------------
 
 - Android SDK 24
-- Android Build Tools v25.0.3
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/NavigationDrawer/Application/build.gradle b/prebuilts/gradle/NavigationDrawer/Application/build.gradle
index f48adf5..8f86751 100644
--- a/prebuilts/gradle/NavigationDrawer/Application/build.gradle
+++ b/prebuilts/gradle/NavigationDrawer/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,6 +13,9 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/NavigationDrawer/README.md b/prebuilts/gradle/NavigationDrawer/README.md
index 7b93a02..b1de4a4 100644
--- a/prebuilts/gradle/NavigationDrawer/README.md
+++ b/prebuilts/gradle/NavigationDrawer/README.md
@@ -8,8 +8,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/NetworkConnect/Application/build.gradle b/prebuilts/gradle/NetworkConnect/Application/build.gradle
index 3c9428a..271193c 100644
--- a/prebuilts/gradle/NetworkConnect/Application/build.gradle
+++ b/prebuilts/gradle/NetworkConnect/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 11
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/NetworkConnect/README.md b/prebuilts/gradle/NetworkConnect/README.md
index 7bda6c7..0186a8d 100644
--- a/prebuilts/gradle/NetworkConnect/README.md
+++ b/prebuilts/gradle/NetworkConnect/README.md
@@ -31,8 +31,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/NfcProvisioning/Application/build.gradle b/prebuilts/gradle/NfcProvisioning/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/NfcProvisioning/Application/build.gradle
+++ b/prebuilts/gradle/NfcProvisioning/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/NfcProvisioning/README.md b/prebuilts/gradle/NfcProvisioning/README.md
index 1451b6b..8a36400 100644
--- a/prebuilts/gradle/NfcProvisioning/README.md
+++ b/prebuilts/gradle/NfcProvisioning/README.md
@@ -33,8 +33,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/NotificationChannels/Application/build.gradle b/prebuilts/gradle/NotificationChannels/Application/build.gradle
index da109ce..e5ed7ff 100644
--- a/prebuilts/gradle/NotificationChannels/Application/build.gradle
+++ b/prebuilts/gradle/NotificationChannels/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion "android-O"
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion "android-O"
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/NotificationChannels/README.md b/prebuilts/gradle/NotificationChannels/README.md
index 5342fb1..737333f 100644
--- a/prebuilts/gradle/NotificationChannels/README.md
+++ b/prebuilts/gradle/NotificationChannels/README.md
@@ -41,8 +41,8 @@
 Pre-requisites
 --------------
 
-- Android SDK Preview O
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Notifications/Application/build.gradle b/prebuilts/gradle/Notifications/Application/build.gradle
index 2ab2620..16debb7 100644
--- a/prebuilts/gradle/Notifications/Application/build.gradle
+++ b/prebuilts/gradle/Notifications/Application/build.gradle
@@ -19,12 +19,13 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
+    compile 'com.android.support.constraint:constraint-layout:1.0.2'
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     wearApp project(':Wearable')
 }
 
@@ -38,9 +39,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java b/prebuilts/gradle/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java
index 4ade3ed..9ee8152 100644
--- a/prebuilts/gradle/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java
+++ b/prebuilts/gradle/Notifications/Application/src/main/java/com/example/android/support/wearable/notifications/MainActivity.java
@@ -58,12 +58,12 @@
     private CheckBox mIncludeContentIntentCheckbox;
     private CheckBox mVibrateCheckbox;
     private BackgroundPickers mBackgroundPickers;
-    private int postedNotificationCount = 0;
+    private int mPostedNotificationCount = 0;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
+        setContentView(R.layout.activity_main);
 
         mHandler = new Handler(this);
         mTextChangedListener = new UpdateNotificationsOnTextChangeListener();
@@ -172,15 +172,25 @@
     private void updateTextEditors(NotificationPreset preset) {
         mTitleEditText.setText(getString(preset.titleResId));
         mTextEditText.setText(getString(preset.textResId));
+
+        View[] presetViews = {
+                findViewById(R.id.title_label),
+                findViewById(R.id.title_editor),
+                findViewById(R.id.text_label),
+                findViewById(R.id.text_editor)
+        };
+
         if (preset == NotificationPresets.BASIC) {
-            findViewById(R.id.title_edit_field).setVisibility(View.VISIBLE);
+            for (View v : presetViews) {
+                v.setVisibility(View.VISIBLE);
+            }
             mTitleEditText.addTextChangedListener(mTextChangedListener);
-            findViewById(R.id.text_edit_field).setVisibility(View.VISIBLE);
             mTextEditText.addTextChangedListener(mTextChangedListener);
         } else {
-            findViewById(R.id.title_edit_field).setVisibility(View.GONE);
+            for (View v : presetViews) {
+                v.setVisibility(View.GONE);
+            }
             mTitleEditText.removeTextChangedListener(mTextChangedListener);
-            findViewById(R.id.text_edit_field).setVisibility(View.GONE);
             mTextEditText.removeTextChangedListener(mTextChangedListener);
         }
     }
@@ -195,9 +205,10 @@
 
         if (cancelExisting) {
             // Cancel all existing notifications to trigger fresh-posting behavior: For example,
-            // switching from HIGH to LOW priority does not cause a reordering in Notification Shade.
+            // switching from HIGH to LOW priority does not cause a reordering in Notification
+            // Shade.
             NotificationManagerCompat.from(this).cancelAll();
-            postedNotificationCount = 0;
+            mPostedNotificationCount = 0;
 
             // Post the updated notifications on a delay to avoid a cancel+post race condition
             // with notification manager.
@@ -215,12 +226,27 @@
         sendBroadcast(new Intent(NotificationIntentReceiver.ACTION_ENABLE_MESSAGES)
                 .setClass(this, NotificationIntentReceiver.class));
 
+        Notification[] notifications = buildNotifications();
+
+        // Post new notifications
+        NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(this);
+        for (int i = 0; i < notifications.length; i++) {
+            notificationManagerCompat.notify(i, notifications[i]);
+        }
+        // Cancel any that are beyond the current count.
+        for (int i = notifications.length; i < mPostedNotificationCount; i++) {
+            notificationManagerCompat.cancel(i);
+        }
+        mPostedNotificationCount = notifications.length;
+    }
+
+    /**
+     * Build the sample notifications
+     */
+
+    private Notification[] buildNotifications() {
         NotificationPreset preset = NotificationPresets.PRESETS[
                 mPresetSpinner.getSelectedItemPosition()];
-        CharSequence titlePreset = mTitleEditText.getText();
-        CharSequence textPreset = mTextEditText.getText();
-        PriorityPreset priorityPreset = PriorityPresets.PRESETS[
-                mPrioritySpinner.getSelectedItemPosition()];
         ActionsPreset actionsPreset = ActionsPresets.PRESETS[
                 mActionsSpinner.getSelectedItemPosition()];
         if (preset.actionsRequired() && actionsPreset == ActionsPresets.NO_ACTIONS_PRESET) {
@@ -230,26 +256,16 @@
                     actionsPreset), true);
         }
         NotificationPreset.BuildOptions options = new NotificationPreset.BuildOptions(
-                titlePreset,
-                textPreset,
-                priorityPreset,
+                mTitleEditText.getText(),
+                mTextEditText.getText(),
+                PriorityPresets.PRESETS[mPrioritySpinner.getSelectedItemPosition()],
                 actionsPreset,
                 mIncludeLargeIconCheckbox.isChecked(),
                 mLocalOnlyCheckbox.isChecked(),
                 mIncludeContentIntentCheckbox.isChecked(),
                 mVibrateCheckbox.isChecked(),
                 mBackgroundPickers.getRes());
-        Notification[] notifications = preset.buildNotifications(this, options);
-
-        // Post new notifications
-        for (int i = 0; i < notifications.length; i++) {
-            NotificationManagerCompat.from(this).notify(i, notifications[i]);
-        }
-        // Cancel any that are beyond the current count.
-        for (int i = notifications.length; i < postedNotificationCount; i++) {
-            NotificationManagerCompat.from(this).cancel(i);
-        }
-        postedNotificationCount = notifications.length;
+        return preset.buildNotifications(this, options);
     }
 
     @Override
@@ -272,17 +288,14 @@
         }
 
         @Override
-        public void onNothingSelected(AdapterView<?> adapterView) {
-        }
+        public void onNothingSelected(AdapterView<?> adapterView) {}
     }
 
     private class UpdateNotificationsOnTextChangeListener implements TextWatcher {
         @Override
-        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-        }
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
 
-        public void onTextChanged(CharSequence s, int start, int before, int count) {
-        }
+        public void onTextChanged(CharSequence s, int start, int before, int count) {}
 
         @Override
         public void afterTextChanged(Editable s) {
diff --git a/prebuilts/gradle/Notifications/Application/src/main/res/drawable/selected_background.xml b/prebuilts/gradle/Notifications/Application/src/main/res/drawable/selected_background.xml
index 5852dd8..f470fc8 100644
--- a/prebuilts/gradle/Notifications/Application/src/main/res/drawable/selected_background.xml
+++ b/prebuilts/gradle/Notifications/Application/src/main/res/drawable/selected_background.xml
@@ -17,11 +17,11 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
     <padding
-        android:top="4dp"
-        android:bottom="4dp"
-        android:left="4dp"
-        android:right="4dp"/>
+        android:top="@dimen/shape_padding"
+        android:bottom="@dimen/shape_padding"
+        android:left="@dimen/shape_padding"
+        android:right="@dimen/shape_padding"/>
     <stroke
-        android:width="4dp"
-        android:color="@android:color/holo_blue_bright" />
+        android:width="@dimen/shape_stroke_width"
+        android:color="@color/blue" />
 </shape>
diff --git a/prebuilts/gradle/Notifications/Application/src/main/res/drawable/unselected_background.xml b/prebuilts/gradle/Notifications/Application/src/main/res/drawable/unselected_background.xml
index 1613167..a546897 100644
--- a/prebuilts/gradle/Notifications/Application/src/main/res/drawable/unselected_background.xml
+++ b/prebuilts/gradle/Notifications/Application/src/main/res/drawable/unselected_background.xml
@@ -17,11 +17,11 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
     <padding
-        android:top="4dp"
-        android:bottom="4dp"
-        android:left="4dp"
-        android:right="4dp"/>
+        android:top="@dimen/shape_padding"
+        android:bottom="@dimen/shape_padding"
+        android:left="@dimen/shape_padding"
+        android:right="@dimen/shape_padding"/>
     <stroke
-        android:width="4dp"
-        android:color="#ff000000" />
+        android:width="@dimen/shape_stroke_width"
+        android:color="@android:color/black" />
 </shape>
diff --git a/prebuilts/gradle/Notifications/Application/src/main/res/layout/activity_main.xml b/prebuilts/gradle/Notifications/Application/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..2a54ebf
--- /dev/null
+++ b/prebuilts/gradle/Notifications/Application/src/main/res/layout/activity_main.xml
@@ -0,0 +1,232 @@
+<?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"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <android.support.constraint.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        tools:layout_editor_absoluteX="0dp"
+        tools:layout_editor_absoluteY="81dp">
+
+        <TextView
+            android:id="@+id/textView"
+            android:layout_width="368dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="8dp"
+            android:text="@string/properties"
+            android:textAllCaps="true"
+            android:textColor="@color/blue"
+            android:textSize="18sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <TextView
+            android:id="@+id/textView2"
+            android:layout_width="48dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="16dp"
+            android:minWidth="0dp"
+            android:text="@string/preset"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/textView"
+            tools:layout_editor_absoluteX="8dp" />
+
+        <Spinner
+            android:id="@+id/preset_spinner"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="8dp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toEndOf="@+id/textView2"
+            android:layout_marginTop="12dp"
+            app:layout_constraintTop_toBottomOf="@+id/textView" />
+
+        <TextView
+            android:id="@+id/textView3"
+            android:layout_width="48dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="16dp"
+            android:text="@string/priority"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/textView2"
+            tools:layout_editor_absoluteX="8dp" />
+
+        <Spinner
+            android:id="@+id/priority_spinner"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="8dp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toEndOf="@+id/textView3"
+            tools:layout_editor_absoluteY="83dp"
+            android:layout_marginTop="14dp"
+            app:layout_constraintTop_toBottomOf="@+id/preset_spinner" />
+
+        <TextView
+            android:id="@+id/textView4"
+            android:layout_width="48dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="16dp"
+            android:text="@string/actions"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/textView3"
+            tools:layout_editor_absoluteX="8dp" />
+
+        <Spinner
+            android:id="@+id/actions_spinner"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="8dp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toEndOf="@+id/textView4"
+            tools:layout_editor_absoluteY="118dp"
+            android:layout_marginTop="11dp"
+            app:layout_constraintTop_toBottomOf="@+id/priority_spinner" />
+
+        <TextView
+            android:id="@+id/title_label"
+            android:layout_width="48dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="16dp"
+            android:labelFor="@+id/title_editor"
+            android:text="@string/title"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/textView4"
+            tools:layout_editor_absoluteX="8dp" />
+
+        <EditText
+            android:id="@id/title_editor"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="8dp"
+            android:ems="10"
+            android:inputType="textPersonName"
+            app:layout_constraintBaseline_toBaselineOf="@+id/title_label"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toEndOf="@+id/title_label" />
+
+        <TextView
+            android:id="@+id/text_label"
+            android:layout_width="48dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="16dp"
+            android:labelFor="@+id/text_editor"
+            android:text="@string/text"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/title_label"
+            tools:layout_editor_absoluteX="8dp" />
+
+        <EditText
+            android:id="@id/text_editor"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="8dp"
+            android:ems="10"
+            android:inputType="textPersonName"
+            app:layout_constraintBaseline_toBaselineOf="@+id/text_label"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toEndOf="@+id/text_label" />
+
+        <CheckBox
+            android:id="@+id/include_large_icon_checkbox"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="16dp"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="16dp"
+            android:text="@string/include_large_icon"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/text_label" />
+
+        <CheckBox
+            android:id="@+id/local_only_checkbox"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="16dp"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="8dp"
+            android:text="@string/local_only"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/include_large_icon_checkbox" />
+
+        <CheckBox
+            android:id="@+id/include_content_intent_checkbox"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="16dp"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="8dp"
+            android:text="@string/include_content_intent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/local_only_checkbox" />
+
+        <CheckBox
+            android:id="@+id/vibrate_checkbox"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="16dp"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="8dp"
+            android:text="@string/vibrate"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/include_content_intent_checkbox" />
+
+        <LinearLayout
+            android:id="@+id/background_pickers"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="8dp"
+            android:layout_marginEnd="16dp"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="8dp"
+            android:orientation="vertical"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/vibrate_checkbox" />
+    </android.support.constraint.ConstraintLayout>
+</ScrollView>
diff --git a/prebuilts/gradle/Notifications/Application/src/main/res/layout/main.xml b/prebuilts/gradle/Notifications/Application/src/main/res/layout/main.xml
deleted file mode 100644
index 3068ddc..0000000
--- a/prebuilts/gradle/Notifications/Application/src/main/res/layout/main.xml
+++ /dev/null
@@ -1,173 +0,0 @@
-
-<!-- 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.
--->
-
-<ScrollView 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: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.support.wearable.notifications.MainActivity"
-        tools:ignore="MergeRootFrame">
-
-    <LinearLayout android:id="@+id/container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical">
-
-        <include layout="@layout/layout_divider" />
-
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal">
-
-            <TextView
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:minWidth="@dimen/editor_spinner_caption_min_width"
-                    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-                    android:gravity="center_vertical"
-                    android:text="@string/preset" />
-
-            <Spinner android:id="@+id/preset_spinner"
-                    android:layout_marginLeft="10dp"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content" />
-
-        </LinearLayout>
-
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal">
-
-            <TextView
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:minWidth="@dimen/editor_spinner_caption_min_width"
-                    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-                    android:gravity="center_vertical"
-                    android:text="@string/priority" />
-
-            <Spinner android:id="@+id/priority_spinner"
-                    android:layout_marginLeft="10dp"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content" />
-
-        </LinearLayout>
-
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal">
-
-            <TextView
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:minWidth="@dimen/editor_spinner_caption_min_width"
-                    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-                    android:gravity="center_vertical"
-                    android:text="@string/actions" />
-
-            <Spinner android:id="@+id/actions_spinner"
-                    android:layout_marginLeft="10dp"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content" />
-
-        </LinearLayout>
-
-        <LinearLayout
-                android:id="@+id/title_edit_field"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal">
-
-            <TextView
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:minWidth="@dimen/editor_spinner_caption_min_width"
-                    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-                    android:gravity="center_vertical"
-                    android:text="@string/title" />
-
-            <EditText android:id="@+id/title_editor"
-                    android:layout_marginLeft="10dp"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content" />
-
-        </LinearLayout>
-
-        <LinearLayout
-                android:id="@+id/text_edit_field"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal">
-
-            <TextView
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:minWidth="@dimen/editor_spinner_caption_min_width"
-                    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-                    android:gravity="center_vertical"
-                    android:text="@string/text" />
-
-            <EditText android:id="@+id/text_editor"
-                    android:layout_marginLeft="10dp"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content" />
-
-        </LinearLayout>
-
-        <CheckBox android:id="@+id/include_large_icon_checkbox"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:paddingTop="@dimen/editor_item_padding_top"
-                android:paddingBottom="@dimen/editor_item_padding_bottom"
-                android:text="@string/include_large_icon" />
-
-        <CheckBox android:id="@+id/local_only_checkbox"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:paddingTop="@dimen/editor_item_padding_top"
-                android:paddingBottom="@dimen/editor_item_padding_bottom"
-                android:text="@string/local_only" />
-
-        <CheckBox android:id="@+id/include_content_intent_checkbox"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:paddingTop="@dimen/editor_item_padding_top"
-                android:paddingBottom="@dimen/editor_item_padding_bottom"
-                android:text="@string/include_content_intent" />
-
-        <CheckBox android:id="@+id/vibrate_checkbox"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:paddingTop="@dimen/editor_item_padding_top"
-                  android:paddingBottom="@dimen/editor_item_padding_bottom"
-                  android:text="@string/vibrate" />
-
-        <LinearLayout android:id="@+id/background_pickers"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical">
-        </LinearLayout>
-
-    </LinearLayout>
-
-</ScrollView>
diff --git a/prebuilts/gradle/Notifications/Application/src/main/res/values/colors.xml b/prebuilts/gradle/Notifications/Application/src/main/res/values/colors.xml
index fbcf956..118f3d4 100644
--- a/prebuilts/gradle/Notifications/Application/src/main/res/values/colors.xml
+++ b/prebuilts/gradle/Notifications/Application/src/main/res/values/colors.xml
@@ -15,5 +15,6 @@
 -->
 
 <resources>
-    <color name="divider_text">@android:color/holo_blue_dark</color>
+    <color name="blue">#0000FF</color>
+    <color name="divider_text">@color/blue</color>
 </resources>
diff --git a/prebuilts/gradle/Notifications/Application/src/main/res/values/dimens.xml b/prebuilts/gradle/Notifications/Application/src/main/res/values/dimens.xml
index fd97910..77da63e 100644
--- a/prebuilts/gradle/Notifications/Application/src/main/res/values/dimens.xml
+++ b/prebuilts/gradle/Notifications/Application/src/main/res/values/dimens.xml
@@ -26,4 +26,6 @@
 
     <dimen name="image_picker_item_side">48dp</dimen>
 
+    <dimen name="shape_padding">4dp</dimen>
+    <dimen name="shape_stroke_width">4dp</dimen>
 </resources>
diff --git a/prebuilts/gradle/Notifications/README.md b/prebuilts/gradle/Notifications/README.md
index 83862b8..888c402 100644
--- a/prebuilts/gradle/Notifications/README.md
+++ b/prebuilts/gradle/Notifications/README.md
@@ -23,8 +23,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Notifications/Wearable/build.gradle b/prebuilts/gradle/Notifications/Wearable/build.gradle
index c393601..968e76c 100644
--- a/prebuilts/gradle/Notifications/Wearable/build.gradle
+++ b/prebuilts/gradle/Notifications/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/Notifications/Wearable/src/main/res/layout/activity_notification_display.xml b/prebuilts/gradle/Notifications/Wearable/src/main/res/layout/activity_notification_display.xml
index 7a329d2..d91f6aa 100644
--- a/prebuilts/gradle/Notifications/Wearable/src/main/res/layout/activity_notification_display.xml
+++ b/prebuilts/gradle/Notifications/Wearable/src/main/res/layout/activity_notification_display.xml
@@ -22,11 +22,11 @@
     <TextView android:id="@+id/title"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:textSize="16sp"
-            android:padding="8dp"
+            android:textSize="@dimen/default_text_size"
+            android:padding="@dimen/default_padding"
             android:gravity="center_vertical|center_horizontal"
-            android:textColor="#7777FF"
-            android:shadowColor="#222299"
+            android:textColor="@color/notification_display_text_color"
+            android:shadowColor="@color/notification_display_shadow_color"
             android:shadowRadius="2"
             android:shadowDx="1"
             android:shadowDy="1"
diff --git a/prebuilts/gradle/Notifications/Wearable/src/main/res/values/colors.xml b/prebuilts/gradle/Notifications/Wearable/src/main/res/values/colors.xml
index 10fad66..a81e1bc 100644
--- a/prebuilts/gradle/Notifications/Wearable/src/main/res/values/colors.xml
+++ b/prebuilts/gradle/Notifications/Wearable/src/main/res/values/colors.xml
@@ -18,4 +18,6 @@
     <color name="wl_blue">#2878ff</color>
     <color name="wl_gray">#c1c1c1</color>
     <color name="text_color">#434343</color>
+    <color name="notification_display_text_color">#7777FF</color>
+    <color name="notification_display_shadow_color">#222299</color>
 </resources>
diff --git a/prebuilts/gradle/Notifications/Wearable/src/main/res/values/dimens.xml b/prebuilts/gradle/Notifications/Wearable/src/main/res/values/dimens.xml
index 50214e6..8698c3c 100644
--- a/prebuilts/gradle/Notifications/Wearable/src/main/res/values/dimens.xml
+++ b/prebuilts/gradle/Notifications/Wearable/src/main/res/values/dimens.xml
@@ -19,5 +19,7 @@
     <dimen name="activity_horizontal_margin">16dp</dimen>
     <dimen name="activity_vertical_margin">16dp</dimen>
     <dimen name="animation_range">60dp</dimen>
+    <dimen name="default_text_size">16sp</dimen>
+    <dimen name="default_padding">8dp</dimen>
 
 </resources>
diff --git a/prebuilts/gradle/PdfRendererBasic/Application/build.gradle b/prebuilts/gradle/PdfRendererBasic/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/PdfRendererBasic/Application/build.gradle
+++ b/prebuilts/gradle/PdfRendererBasic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/PdfRendererBasic/README.md b/prebuilts/gradle/PdfRendererBasic/README.md
index 8050685..768cc90 100644
--- a/prebuilts/gradle/PdfRendererBasic/README.md
+++ b/prebuilts/gradle/PdfRendererBasic/README.md
@@ -28,8 +28,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/PermissionRequest/Application/build.gradle b/prebuilts/gradle/PermissionRequest/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/PermissionRequest/Application/build.gradle
+++ b/prebuilts/gradle/PermissionRequest/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/PermissionRequest/README.md b/prebuilts/gradle/PermissionRequest/README.md
index b58cca9..943d0bc 100644
--- a/prebuilts/gradle/PermissionRequest/README.md
+++ b/prebuilts/gradle/PermissionRequest/README.md
@@ -46,8 +46,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/PictureInPicture/.google/packaging.yaml b/prebuilts/gradle/PictureInPicture/.google/packaging.yaml
index 640b2dd..0e424b8 100644
--- a/prebuilts/gradle/PictureInPicture/.google/packaging.yaml
+++ b/prebuilts/gradle/PictureInPicture/.google/packaging.yaml
@@ -6,14 +6,15 @@
 ---
 status:       PUBLISHED
 technologies: [Android]
-categories:   [Media, Android O Preview]
+categories:   [Media, Android Oreo]
 languages:    [Java]
 solutions:    [Mobile]
 github:       android-PictureInPicture
 level:        ADVANCED
 icon:         screenshots/icon-web.png
 apiRefs:
-    - android:android.app.PictureInPictureArgs
+    - android:android.app.PictureInPictureParams
     - android:android.app.RemoteAction
     - android:android.app.PendingIntent
+    - android:android.support.v4.media.session.MediaSessionCompat
 license: apache2
diff --git a/prebuilts/gradle/PictureInPicture/README.md b/prebuilts/gradle/PictureInPicture/README.md
index 51768bf..265336c 100644
--- a/prebuilts/gradle/PictureInPicture/README.md
+++ b/prebuilts/gradle/PictureInPicture/README.md
@@ -10,9 +10,8 @@
 Introduction
 ------------
 
-The O Developer Preview allows activities to launch in Picture-in-Picture (PiP) mode. PiP is a
-special type of [multi-window][1] mode mostly used for video playback. PiP mode is already available
-for [Android TV][2]; the O Developer Preview makes the feature available on other Android devices.
+As of Android O, activities can launch in [Picture-in-Picture (PiP)][1] mode. PiP is a
+special type of [multi-window][2] mode mostly used for video playback.
 
 The app is *paused* when it enters PiP mode, but it should continue showing content. For this
 reason, you should make sure your app does not pause playback in its [onPause()][3]
@@ -20,36 +19,35 @@
 Lifecycle][5].
 
 To specify that your activity can use PIP mode, set `android:supportsPictureInPicture` to `true` in
-the manifest. (Beginning with the O Developer Preview, you do not need to set
-`android:resizeableActivity` to `true` if you are supporting PIP mode, either on Android TV or on
-other Android devices; you only need to `setrandroid:resizeableActivity` if your activity supports
-other multi-window modes.)
+the manifest. (Beginning with Android O, you do not need to set
+`android:resizeableActivity` to `true` if you are supporting PIP mode you only need to
+`setrandroid:resizeableActivity` if your activity supports other multi-window modes.)
 
-You can pass a [PictureInPictureArgs][6] to [enterPictureInPictureMode()][7] to specify how an
+You can pass a [PictureInPictureParams][6] to [enterPictureInPictureMode()][7] to specify how an
 activity should behave when it is in PiP mode. You can also use it to call
-[setPictureInPictureArgs()][8] and update the current behavior. If the app is in not PiP mode, it
+[setPictureInPictureParams()][8] and update the current behavior. If the app is in not PiP mode, it
 will be used for later call of [enterPictureInPictureMode()][7].
 
-With a [PictureInPictureArgs][6], you can specify aspect ratio of PiP activity and action items
+With a [PictureInPictureParams][6], you can specify aspect ratio of PiP activity and action items
 available for PiP mode. The aspect ratio is used when the activity is in PiP mode. The action items
 are used as menu items in PiP mode. You can use a [PendingIntent][9] to specify what to do when the
 item is selected.
 
-[1]: https://developer.android.com/guide/topics/ui/multi-window.html
-[2]: https://developer.android.com/training/tv/playback/picture-in-picture.html
+[1]: https://developer.android.com/guide/topics/ui/picture-in-picture.html
+[2]: https://developer.android.com/guide/topics/ui/multi-window.html
 [3]: https://developer.android.com/reference/android/app/Activity.html#onPause()
 [4]: https://developer.android.com/reference/android/app/Activity.html#onStop()
 [5]: https://developer.android.com/guide/topics/ui/multi-window.html#lifecycle
-[6]: https://developer.android.com/reference/android/app/PictureInPictureArgs.html
-[7]: https://developer.android.com/reference/android/app/Activity.html#enterPictureInPictureMode(android.app.PictureInPictureArgs)
-[8]: https://developer.android.com/reference/android/app/Activity.html#setPictureInPictureArgs(android.app.PictureInPictureArgs)
+[6]: https://developer.android.com/reference/android/app/PictureInPictureParams.html
+[7]: https://developer.android.com/reference/android/app/Activity.html#enterPictureInPictureMode(android.app.PictureInPictureParams)
+[8]: https://developer.android.com/reference/android/app/Activity.html#setPictureInPictureParams(android.app.PictureInPictureParams)
 [9]: https://developer.android.com/reference/android/app/PendingIntent.html
 
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/PictureInPicture/app/app.iml b/prebuilts/gradle/PictureInPicture/app/app.iml
new file mode 100644
index 0000000..3e9c61f
--- /dev/null
+++ b/prebuilts/gradle/PictureInPicture/app/app.iml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="android-gradle" name="Android-Gradle">
+      <configuration>
+        <option name="GRADLE_PROJECT_PATH" value=":app" />
+      </configuration>
+    </facet>
+    <facet type="android" name="Android">
+      <configuration>
+        <option name="SELECTED_BUILD_VARIANT" value="debug" />
+        <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
+        <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
+        <afterSyncTasks>
+          <task>generateDebugSources</task>
+        </afterSyncTasks>
+        <option name="ALLOW_USER_CONFIGURATION" value="false" />
+        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
+        <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
+        <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
+        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
+    <output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
+      <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
+    </content>
+    <orderEntry type="jdk" jdkName="Android API 26 Platform" jdkType="Android SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" exported="" scope="TEST" name="espresso-core-2.2.2" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="runner-0.5" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="exposed-instrumentation-api-publish-0.5" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="espresso-idling-resource-2.2.2" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="rules-0.5" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="hamcrest-library-1.3" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="javax.annotation-api-1.2" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="javax.inject-1" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="hamcrest-integration-1.3" level="project" />
+    <orderEntry type="library" exported="" name="support-core-ui-25.3.1" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="javawriter-2.1.1" level="project" />
+    <orderEntry type="library" exported="" name="support-v4-25.3.1" level="project" />
+    <orderEntry type="library" exported="" name="support-media-compat-25.3.1" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="hamcrest-core-1.3" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="junit-4.12" level="project" />
+    <orderEntry type="library" exported="" name="support-annotations-25.3.1" level="project" />
+    <orderEntry type="library" exported="" name="appcompat-v7-25.3.1" level="project" />
+    <orderEntry type="library" exported="" name="support-vector-drawable-25.3.1" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="jsr305-2.0.1" level="project" />
+    <orderEntry type="library" exported="" name="support-compat-25.3.1" level="project" />
+    <orderEntry type="library" exported="" name="support-core-utils-25.3.1" level="project" />
+    <orderEntry type="library" exported="" name="support-fragment-25.3.1" level="project" />
+    <orderEntry type="library" exported="" name="animated-vector-drawable-25.3.1" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/prebuilts/gradle/PictureInPicture/app/build.gradle b/prebuilts/gradle/PictureInPicture/app/build.gradle
index 25f4577..0c7760f 100644
--- a/prebuilts/gradle/PictureInPicture/app/build.gradle
+++ b/prebuilts/gradle/PictureInPicture/app/build.gradle
@@ -1,12 +1,12 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 'android-O'
-    buildToolsVersion "25.0.2"
+    compileSdkVersion 26
+    buildToolsVersion "26.0.2"
     defaultConfig {
         applicationId "com.example.android.pictureinpicture"
-        minSdkVersion 'O'
-        targetSdkVersion 'O'
+        minSdkVersion 26
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -24,7 +24,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:25.3.1'
+    compile 'com.android.support:appcompat-v7:26.1.0'
+    compile 'com.android.support:support-media-compat:26.1.0'
 
     testCompile 'junit:junit:4.12'
 }
diff --git a/prebuilts/gradle/PictureInPicture/app/src/androidTest/java/com/example/android/pictureinpicture/MainActivityTest.java b/prebuilts/gradle/PictureInPicture/app/src/androidTest/java/com/example/android/pictureinpicture/MainActivityTest.java
index 6f1b220..03033c5 100644
--- a/prebuilts/gradle/PictureInPicture/app/src/androidTest/java/com/example/android/pictureinpicture/MainActivityTest.java
+++ b/prebuilts/gradle/PictureInPicture/app/src/androidTest/java/com/example/android/pictureinpicture/MainActivityTest.java
@@ -68,7 +68,7 @@
             public void run() {
                 // We are now in Picture-in-Picture mode
                 assertTrue(rule.getActivity().isInPictureInPictureMode());
-                final MovieView view = (MovieView) rule.getActivity().findViewById(R.id.movie);
+                final MovieView view = rule.getActivity().findViewById(R.id.movie);
                 assertNotNull(view);
                 // The video should still be playing
                 assertTrue(view.isPlaying());
diff --git a/prebuilts/gradle/PictureInPicture/app/src/androidTest/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivityTest.java b/prebuilts/gradle/PictureInPicture/app/src/androidTest/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivityTest.java
new file mode 100644
index 0000000..349f963
--- /dev/null
+++ b/prebuilts/gradle/PictureInPicture/app/src/androidTest/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivityTest.java
@@ -0,0 +1,202 @@
+/*
+ * 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.pictureinpicture;
+
+import android.content.pm.ActivityInfo;
+import android.media.session.PlaybackState;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.media.session.PlaybackStateCompat;
+import android.view.View;
+
+import com.example.android.pictureinpicture.widget.MovieView;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.core.AllOf.allOf;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+
+@RunWith(AndroidJUnit4.class)
+public class MediaSessionPlaybackActivityTest {
+
+    @Rule
+    public ActivityTestRule<MediaSessionPlaybackActivity> rule =
+            new ActivityTestRule<>(MediaSessionPlaybackActivity.class);
+
+    @Test
+    public void movie_playingOnPip() throws Throwable {
+        // The movie should be playing on start
+        onView(withId(R.id.movie))
+                .check(matches(allOf(isDisplayed(), isPlaying())))
+                .perform(showControls());
+        // Click on the button to enter Picture-in-Picture mode
+        onView(withId(R.id.minimize)).perform(click());
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        // The Activity is paused. We cannot use Espresso to test paused activities.
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // We are now in Picture-in-Picture mode
+                assertTrue(rule.getActivity().isInPictureInPictureMode());
+                final MovieView view = rule.getActivity().findViewById(R.id.movie);
+                assertNotNull(view);
+                // The video should still be playing
+                assertTrue(view.isPlaying());
+
+                // The media session state should be playing.
+                assertMediaStateIs(PlaybackStateCompat.STATE_PLAYING);
+            }
+        });
+    }
+
+    @Test
+    public void movie_pauseAndResume() throws Throwable {
+        // The movie should be playing on start
+        onView(withId(R.id.movie))
+                .check(matches(allOf(isDisplayed(), isPlaying())))
+                .perform(showControls());
+        // Pause
+        onView(withId(R.id.toggle)).perform(click());
+        onView(withId(R.id.movie)).check(matches((not(isPlaying()))));
+        // The media session state should be paused.
+        assertMediaStateIs(PlaybackStateCompat.STATE_PAUSED);
+        // Resume
+        onView(withId(R.id.toggle)).perform(click());
+        onView(withId(R.id.movie)).check(matches(isPlaying()));
+        // The media session state should be playing.
+        assertMediaStateIs(PlaybackStateCompat.STATE_PLAYING);
+    }
+
+    @Test
+    public void fullscreen_enabledOnLandscape() throws Throwable {
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                rule.getActivity()
+                        .setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+            }
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final View decorView = rule.getActivity().getWindow().getDecorView();
+                assertThat(decorView.getSystemUiVisibility(),
+                        hasFlag(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN));
+            }
+        });
+    }
+
+    @Test
+    public void fullscreen_disabledOnPortrait() throws Throwable {
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                rule.getActivity()
+                        .setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+            }
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        rule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final View decorView = rule.getActivity().getWindow().getDecorView();
+                assertThat(decorView.getSystemUiVisibility(),
+                        not(hasFlag(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)));
+            }
+        });
+    }
+
+    private void assertMediaStateIs(@PlaybackStateCompat.State int expectedState) {
+        PlaybackState state = rule.getActivity().getMediaController().getPlaybackState();
+        assertNotNull(state);
+        assertThat(
+                "MediaSession is not in the correct state",
+                state.getState(),
+                is(equalTo(expectedState)));
+    }
+
+    private static Matcher<? super View> isPlaying() {
+        return new TypeSafeMatcher<View>() {
+            @Override
+            protected boolean matchesSafely(View view) {
+                return ((MovieView) view).isPlaying();
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("MovieView is playing");
+            }
+        };
+    }
+
+    private static ViewAction showControls() {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return isAssignableFrom(MovieView.class);
+            }
+
+            @Override
+            public String getDescription() {
+                return "Show controls of MovieView";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+                ((MovieView) view).showControls();
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+
+    private static Matcher<? super Integer> hasFlag(final int flag) {
+        return new TypeSafeMatcher<Integer>() {
+            @Override
+            protected boolean matchesSafely(Integer i) {
+                return (i & flag) == flag;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Flag integer contains " + flag);
+            }
+        };
+    }
+
+}
diff --git a/prebuilts/gradle/PictureInPicture/app/src/main/AndroidManifest.xml b/prebuilts/gradle/PictureInPicture/app/src/main/AndroidManifest.xml
index f95bcc8..88928e4 100644
--- a/prebuilts/gradle/PictureInPicture/app/src/main/AndroidManifest.xml
+++ b/prebuilts/gradle/PictureInPicture/app/src/main/AndroidManifest.xml
@@ -34,6 +34,9 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".MediaSessionPlaybackActivity"
+            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+            android:supportsPictureInPicture="true" />
 
     </application>
 
diff --git a/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MainActivity.java b/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MainActivity.java
index b2c41c7..f38729b 100644
--- a/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MainActivity.java
+++ b/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MainActivity.java
@@ -17,7 +17,7 @@
 package com.example.android.pictureinpicture;
 
 import android.app.PendingIntent;
-import android.app.PictureInPictureArgs;
+import android.app.PictureInPictureParams;
 import android.app.RemoteAction;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -29,17 +29,16 @@
 import android.os.Bundle;
 import android.support.annotation.DrawableRes;
 import android.support.v7.app.AppCompatActivity;
+import android.util.Rational;
 import android.view.View;
+import android.widget.Button;
 import android.widget.ScrollView;
 
 import com.example.android.pictureinpicture.widget.MovieView;
 
 import java.util.ArrayList;
 
-
-/**
- * Demonstrates usage of Picture-in-Picture mode on phones and tablets.
- */
+/** Demonstrates usage of Picture-in-Picture mode on phones and tablets. */
 public class MainActivity extends AppCompatActivity {
 
     /** Intent action for media controls from Picture-in-Picture mode. */
@@ -64,7 +63,8 @@
     private static final int CONTROL_TYPE_PAUSE = 2;
 
     /** The arguments to be used for Picture-in-Picture mode. */
-    private final PictureInPictureArgs mPictureInPictureArgs = new PictureInPictureArgs();
+    private final PictureInPictureParams.Builder mPictureInPictureParamsBuilder =
+            new PictureInPictureParams.Builder();
 
     /** This shows the video. */
     private MovieView mMovieView;
@@ -78,82 +78,91 @@
     private String mPlay;
     private String mPause;
 
-    private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View view) {
-            switch (view.getId()) {
-                case R.id.pip:
+    private final View.OnClickListener mOnClickListener =
+            new View.OnClickListener() {
+                @Override
+                public void onClick(View view) {
+                    switch (view.getId()) {
+                        case R.id.pip:
+                            minimize();
+                            break;
+                    }
+                }
+            };
+
+    /** Callbacks from the {@link MovieView} showing the video playback. */
+    private MovieView.MovieListener mMovieListener =
+            new MovieView.MovieListener() {
+
+                @Override
+                public void onMovieStarted() {
+                    // We are playing the video now. In PiP mode, we want to show an action item to
+                    // pause
+                    // the video.
+                    updatePictureInPictureActions(
+                            R.drawable.ic_pause_24dp, mPause, CONTROL_TYPE_PAUSE, REQUEST_PAUSE);
+                }
+
+                @Override
+                public void onMovieStopped() {
+                    // The video stopped or reached its end. In PiP mode, we want to show an action
+                    // item to play the video.
+                    updatePictureInPictureActions(
+                            R.drawable.ic_play_arrow_24dp, mPlay, CONTROL_TYPE_PLAY, REQUEST_PLAY);
+                }
+
+                @Override
+                public void onMovieMinimized() {
+                    // The MovieView wants us to minimize it. We enter Picture-in-Picture mode now.
                     minimize();
-                    break;
-            }
-        }
-    };
-
-    /**
-     * Callbacks from the {@link MovieView} showing the video playback.
-     */
-    private MovieView.MovieListener mMovieListener = new MovieView.MovieListener() {
-
-        @Override
-        public void onMovieStarted() {
-            // We are playing the video now. In PiP mode, we want to show an action item to pause
-            // the video.
-            updatePictureInPictureActions(R.drawable.ic_pause_24dp, mPause, CONTROL_TYPE_PAUSE,
-                    REQUEST_PAUSE);
-        }
-
-        @Override
-        public void onMovieStopped() {
-            // The video stopped or reached its end. In PiP mode, we want to show an action item
-            // to play the video.
-            updatePictureInPictureActions(R.drawable.ic_play_arrow_24dp, mPlay, CONTROL_TYPE_PLAY,
-                    REQUEST_PLAY);
-        }
-
-        @Override
-        public void onMovieMinimized() {
-            // The MovieView wants us to minimize it. We enter Picture-in-Picture mode now.
-            minimize();
-        }
-
-    };
+                }
+            };
 
     /**
      * Update the state of pause/resume action item in Picture-in-Picture mode.
      *
-     * @param iconId      The icon to be used.
-     * @param title       The title text.
-     * @param controlType The type of the action. either {@link #CONTROL_TYPE_PLAY} or
-     *                    {@link #CONTROL_TYPE_PAUSE}.
+     * @param iconId The icon to be used.
+     * @param title The title text.
+     * @param controlType The type of the action. either {@link #CONTROL_TYPE_PLAY} or {@link
+     *     #CONTROL_TYPE_PAUSE}.
      * @param requestCode The request code for the {@link PendingIntent}.
      */
-    void updatePictureInPictureActions(@DrawableRes int iconId, String title, int controlType,
-            int requestCode) {
+    void updatePictureInPictureActions(
+            @DrawableRes int iconId, String title, int controlType, int requestCode) {
         final ArrayList<RemoteAction> actions = new ArrayList<>();
 
         // This is the PendingIntent that is invoked when a user clicks on the action item.
         // You need to use distinct request codes for play and pause, or the PendingIntent won't
         // be properly updated.
-        final PendingIntent intent = PendingIntent.getBroadcast(MainActivity.this,
-                requestCode, new Intent(ACTION_MEDIA_CONTROL)
-                        .putExtra(EXTRA_CONTROL_TYPE, controlType), 0);
+        final PendingIntent intent =
+                PendingIntent.getBroadcast(
+                        MainActivity.this,
+                        requestCode,
+                        new Intent(ACTION_MEDIA_CONTROL).putExtra(EXTRA_CONTROL_TYPE, controlType),
+                        0);
         final Icon icon = Icon.createWithResource(MainActivity.this, iconId);
         actions.add(new RemoteAction(icon, title, title, intent));
 
         // Another action item. This is a fixed action.
-        actions.add(new RemoteAction(
-                Icon.createWithResource(MainActivity.this, R.drawable.ic_info_24dp),
-                getString(R.string.info), getString(R.string.info_description),
-                PendingIntent.getActivity(MainActivity.this, REQUEST_INFO,
-                        new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.info_uri))),
-                        0)));
+        actions.add(
+                new RemoteAction(
+                        Icon.createWithResource(MainActivity.this, R.drawable.ic_info_24dp),
+                        getString(R.string.info),
+                        getString(R.string.info_description),
+                        PendingIntent.getActivity(
+                                MainActivity.this,
+                                REQUEST_INFO,
+                                new Intent(
+                                        Intent.ACTION_VIEW,
+                                        Uri.parse(getString(R.string.info_uri))),
+                                0)));
 
-        mPictureInPictureArgs.setActions(actions);
+        mPictureInPictureParamsBuilder.setActions(actions);
 
         // This is how you can update action items (or aspect ratio) for Picture-in-Picture mode.
         // Note this call can happen even when the app is not in PiP mode. In that case, the
         // arguments will be used for at the next call of #enterPictureInPictureMode.
-        setPictureInPictureArgs(mPictureInPictureArgs);
+        setPictureInPictureParams(mPictureInPictureParamsBuilder.build());
     }
 
     @Override
@@ -166,8 +175,12 @@
         mPause = getString(R.string.pause);
 
         // View references
-        mMovieView = (MovieView) findViewById(R.id.movie);
-        mScrollView = (ScrollView) findViewById(R.id.scroll);
+        mMovieView = findViewById(R.id.movie);
+        mScrollView = findViewById(R.id.scroll);
+
+        Button switchExampleButton = findViewById(R.id.switch_example);
+        switchExampleButton.setText(getString(R.string.switch_media_session));
+        switchExampleButton.setOnClickListener(new SwitchActivityOnClick());
 
         // Set up the video; it automatically starts.
         mMovieView.setMovieListener(mMovieListener);
@@ -185,8 +198,10 @@
     @Override
     protected void onRestart() {
         super.onRestart();
-        // Show the video controls so the video can be easily resumed.
-        mMovieView.showControls();
+        if (!isInPictureInPictureMode()) {
+            // Show the video controls so the video can be easily resumed.
+            mMovieView.showControls();
+        }
     }
 
     @Override
@@ -204,29 +219,33 @@
     }
 
     @Override
-    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
-        super.onPictureInPictureModeChanged(isInPictureInPictureMode);
+    public void onPictureInPictureModeChanged(
+            boolean isInPictureInPictureMode, Configuration configuration) {
+        super.onPictureInPictureModeChanged(isInPictureInPictureMode, configuration);
         if (isInPictureInPictureMode) {
             // Starts receiving events from action items in PiP mode.
-            mReceiver = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    if (intent == null || !ACTION_MEDIA_CONTROL.equals(intent.getAction())) {
-                        return;
-                    }
+            mReceiver =
+                    new BroadcastReceiver() {
+                        @Override
+                        public void onReceive(Context context, Intent intent) {
+                            if (intent == null
+                                    || !ACTION_MEDIA_CONTROL.equals(intent.getAction())) {
+                                return;
+                            }
 
-                    // This is where we are called back from Picture-in-Picture action items.
-                    final int controlType = intent.getIntExtra(EXTRA_CONTROL_TYPE, 0);
-                    switch (controlType) {
-                        case CONTROL_TYPE_PLAY:
-                            mMovieView.play();
-                            break;
-                        case CONTROL_TYPE_PAUSE:
-                            mMovieView.pause();
-                            break;
-                    }
-                }
-            };
+                            // This is where we are called back from Picture-in-Picture action
+                            // items.
+                            final int controlType = intent.getIntExtra(EXTRA_CONTROL_TYPE, 0);
+                            switch (controlType) {
+                                case CONTROL_TYPE_PLAY:
+                                    mMovieView.play();
+                                    break;
+                                case CONTROL_TYPE_PAUSE:
+                                    mMovieView.pause();
+                                    break;
+                            }
+                        }
+                    };
             registerReceiver(mReceiver, new IntentFilter(ACTION_MEDIA_CONTROL));
         } else {
             // We are out of PiP mode. We can stop receiving events from it.
@@ -239,9 +258,7 @@
         }
     }
 
-    /**
-     * Enters Picture-in-Picture mode.
-     */
+    /** Enters Picture-in-Picture mode. */
     void minimize() {
         if (mMovieView == null) {
             return;
@@ -249,9 +266,9 @@
         // Hide the controls in picture-in-picture mode.
         mMovieView.hideControls();
         // Calculate the aspect ratio of the PiP screen.
-        float aspectRatio = (float) mMovieView.getWidth() / mMovieView.getHeight();
-        mPictureInPictureArgs.setAspectRatio(aspectRatio);
-        enterPictureInPictureMode(mPictureInPictureArgs);
+        Rational aspectRatio = new Rational(mMovieView.getWidth(), mMovieView.getHeight());
+        mPictureInPictureParamsBuilder.setAspectRatio(aspectRatio).build();
+        enterPictureInPictureMode(mPictureInPictureParamsBuilder.build());
     }
 
     /**
@@ -278,4 +295,12 @@
         }
     }
 
+    /** Launches {@link MediaSessionPlaybackActivity} and closes this activity. */
+    private class SwitchActivityOnClick implements View.OnClickListener {
+        @Override
+        public void onClick(View view) {
+            startActivity(new Intent(view.getContext(), MediaSessionPlaybackActivity.class));
+            finish();
+        }
+    }
 }
diff --git a/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.java b/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.java
new file mode 100644
index 0000000..90043f1
--- /dev/null
+++ b/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.java
@@ -0,0 +1,340 @@
+/*
+ * 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.pictureinpicture;
+
+import android.app.PictureInPictureParams;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Rational;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ScrollView;
+
+import com.example.android.pictureinpicture.widget.MovieView;
+
+/**
+ * Demonstrates usage of Picture-in-Picture when using {@link
+ * android.support.v4.media.session.MediaSessionCompat}.
+ */
+public class MediaSessionPlaybackActivity extends AppCompatActivity {
+
+    private static final String TAG = "MediaSessionPlaybackActivity";
+
+    public static final long MEDIA_ACTIONS_PLAY_PAUSE =
+            PlaybackStateCompat.ACTION_PLAY
+                    | PlaybackStateCompat.ACTION_PAUSE
+                    | PlaybackStateCompat.ACTION_PLAY_PAUSE;
+
+    public static final long MEDIA_ACTIONS_ALL =
+            MEDIA_ACTIONS_PLAY_PAUSE
+                    | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
+                    | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
+
+    private MediaSessionCompat mSession;
+
+    /** The arguments to be used for Picture-in-Picture mode. */
+    private final PictureInPictureParams.Builder mPictureInPictureParamsBuilder =
+            new PictureInPictureParams.Builder();
+
+    /** This shows the video. */
+    private MovieView mMovieView;
+
+    /** The bottom half of the screen; hidden on landscape */
+    private ScrollView mScrollView;
+
+    private final View.OnClickListener mOnClickListener =
+            new View.OnClickListener() {
+                @Override
+                public void onClick(View view) {
+                    switch (view.getId()) {
+                        case R.id.pip:
+                            minimize();
+                            break;
+                    }
+                }
+            };
+
+    /** Callbacks from the {@link MovieView} showing the video playback. */
+    private MovieView.MovieListener mMovieListener =
+            new MovieView.MovieListener() {
+
+                @Override
+                public void onMovieStarted() {
+                    // We are playing the video now. Update the media session state and the PiP
+                    // window will
+                    // update the actions.
+                    updatePlaybackState(
+                            PlaybackStateCompat.STATE_PLAYING,
+                            mMovieView.getCurrentPosition(),
+                            mMovieView.getVideoResourceId());
+                }
+
+                @Override
+                public void onMovieStopped() {
+                    // The video stopped or reached its end. Update the media session state and the
+                    // PiP window will
+                    // update the actions.
+                    updatePlaybackState(
+                            PlaybackStateCompat.STATE_PAUSED,
+                            mMovieView.getCurrentPosition(),
+                            mMovieView.getVideoResourceId());
+                }
+
+                @Override
+                public void onMovieMinimized() {
+                    // The MovieView wants us to minimize it. We enter Picture-in-Picture mode now.
+                    minimize();
+                }
+            };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        // View references
+        mMovieView = findViewById(R.id.movie);
+        mScrollView = findViewById(R.id.scroll);
+        Button switchExampleButton = findViewById(R.id.switch_example);
+        switchExampleButton.setText(getString(R.string.switch_custom));
+        switchExampleButton.setOnClickListener(new SwitchActivityOnClick());
+
+        // Set up the video; it automatically starts.
+        mMovieView.setMovieListener(mMovieListener);
+        findViewById(R.id.pip).setOnClickListener(mOnClickListener);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        initializeMediaSession();
+    }
+
+    private void initializeMediaSession() {
+        mSession = new MediaSessionCompat(this, TAG);
+        mSession.setFlags(
+                MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
+                        | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
+        mSession.setActive(true);
+        MediaControllerCompat.setMediaController(this, mSession.getController());
+
+        MediaSessionCallback mMediaSessionCallback = new MediaSessionCallback(mMovieView);
+        mSession.setCallback(mMediaSessionCallback);
+
+        int state =
+                mMovieView.isPlaying()
+                        ? PlaybackStateCompat.STATE_PLAYING
+                        : PlaybackStateCompat.STATE_PAUSED;
+        updatePlaybackState(
+                state,
+                MEDIA_ACTIONS_ALL,
+                mMovieView.getCurrentPosition(),
+                mMovieView.getVideoResourceId());
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        // On entering Picture-in-Picture mode, onPause is called, but not onStop.
+        // For this reason, this is the place where we should pause the video playback.
+        mMovieView.pause();
+        mSession.release();
+        mSession = null;
+    }
+
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+        if (!isInPictureInPictureMode()) {
+            // Show the video controls so the video can be easily resumed.
+            mMovieView.showControls();
+        }
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        adjustFullScreen(newConfig);
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (hasFocus) {
+            adjustFullScreen(getResources().getConfiguration());
+        }
+    }
+
+    @Override
+    public void onPictureInPictureModeChanged(
+            boolean isInPictureInPictureMode, Configuration configuration) {
+        super.onPictureInPictureModeChanged(isInPictureInPictureMode, configuration);
+        if (!isInPictureInPictureMode) {
+            // Show the video controls if the video is not playing
+            if (mMovieView != null && !mMovieView.isPlaying()) {
+                mMovieView.showControls();
+            }
+        }
+    }
+
+    /** Enters Picture-in-Picture mode. */
+    void minimize() {
+        if (mMovieView == null) {
+            return;
+        }
+        // Hide the controls in picture-in-picture mode.
+        mMovieView.hideControls();
+        // Calculate the aspect ratio of the PiP screen.
+        Rational aspectRatio = new Rational(mMovieView.getWidth(), mMovieView.getHeight());
+        mPictureInPictureParamsBuilder.setAspectRatio(aspectRatio).build();
+        enterPictureInPictureMode(mPictureInPictureParamsBuilder.build());
+    }
+
+    /**
+     * Adjusts immersive full-screen flags depending on the screen orientation.
+     *
+     * @param config The current {@link Configuration}.
+     */
+    private void adjustFullScreen(Configuration config) {
+        final View decorView = getWindow().getDecorView();
+        if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            decorView.setSystemUiVisibility(
+                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                            | View.SYSTEM_UI_FLAG_FULLSCREEN
+                            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+            mScrollView.setVisibility(View.GONE);
+            mMovieView.setAdjustViewBounds(false);
+        } else {
+            decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+            mScrollView.setVisibility(View.VISIBLE);
+            mMovieView.setAdjustViewBounds(true);
+        }
+    }
+
+    /**
+     * Overloaded method that persists previously set media actions.
+     *
+     * @param state The state of the video, e.g. playing, paused, etc.
+     * @param position The position of playback in the video.
+     * @param mediaId The media id related to the video in the media session.
+     */
+    private void updatePlaybackState(
+            @PlaybackStateCompat.State int state, int position, int mediaId) {
+        long actions = mSession.getController().getPlaybackState().getActions();
+        updatePlaybackState(state, actions, position, mediaId);
+    }
+
+    private void updatePlaybackState(
+            @PlaybackStateCompat.State int state, long playbackActions, int position, int mediaId) {
+        PlaybackStateCompat.Builder builder =
+                new PlaybackStateCompat.Builder()
+                        .setActions(playbackActions)
+                        .setActiveQueueItemId(mediaId)
+                        .setState(state, position, 1.0f);
+        mSession.setPlaybackState(builder.build());
+    }
+
+    /**
+     * Updates the {@link MovieView} based on the callback actions. <br>
+     * Simulates a playlist that will disable actions when you cannot skip through the playlist in a
+     * certain direction.
+     */
+    private class MediaSessionCallback extends MediaSessionCompat.Callback {
+
+        private static final int PLAYLIST_SIZE = 2;
+
+        private MovieView movieView;
+        private int indexInPlaylist;
+
+        public MediaSessionCallback(MovieView movieView) {
+            this.movieView = movieView;
+            indexInPlaylist = 1;
+        }
+
+        @Override
+        public void onPlay() {
+            super.onPlay();
+            movieView.play();
+        }
+
+        @Override
+        public void onPause() {
+            super.onPause();
+            movieView.pause();
+        }
+
+        @Override
+        public void onSkipToNext() {
+            super.onSkipToNext();
+            movieView.startVideo();
+            if (indexInPlaylist < PLAYLIST_SIZE) {
+                indexInPlaylist++;
+                if (indexInPlaylist >= PLAYLIST_SIZE) {
+                    updatePlaybackState(
+                            PlaybackStateCompat.STATE_PLAYING,
+                            MEDIA_ACTIONS_PLAY_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS,
+                            movieView.getCurrentPosition(),
+                            movieView.getVideoResourceId());
+                } else {
+                    updatePlaybackState(
+                            PlaybackStateCompat.STATE_PLAYING,
+                            MEDIA_ACTIONS_ALL,
+                            movieView.getCurrentPosition(),
+                            movieView.getVideoResourceId());
+                }
+            }
+        }
+
+        @Override
+        public void onSkipToPrevious() {
+            super.onSkipToPrevious();
+            movieView.startVideo();
+            if (indexInPlaylist > 0) {
+                indexInPlaylist--;
+                if (indexInPlaylist <= 0) {
+                    updatePlaybackState(
+                            PlaybackStateCompat.STATE_PLAYING,
+                            MEDIA_ACTIONS_PLAY_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_NEXT,
+                            movieView.getCurrentPosition(),
+                            movieView.getVideoResourceId());
+                } else {
+                    updatePlaybackState(
+                            PlaybackStateCompat.STATE_PLAYING,
+                            MEDIA_ACTIONS_ALL,
+                            movieView.getCurrentPosition(),
+                            movieView.getVideoResourceId());
+                }
+            }
+        }
+    }
+
+    private class SwitchActivityOnClick implements View.OnClickListener {
+        @Override
+        public void onClick(View view) {
+            startActivity(new Intent(view.getContext(), MainActivity.class));
+            finish();
+        }
+    }
+}
diff --git a/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.java b/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.java
index 9132c52..0021a7b 100644
--- a/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.java
+++ b/prebuilts/gradle/PictureInPicture/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.java
@@ -40,37 +40,25 @@
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 
-
 /**
  * Provides video playback. There is nothing directly related to Picture-in-Picture here.
  *
  * <p>This is similar to {@link android.widget.VideoView}, but it comes with a custom control
- * (play/pause, fast forward, and fast rewind).</p>
+ * (play/pause, fast forward, and fast rewind).
  */
 public class MovieView extends RelativeLayout {
 
-    /**
-     * Monitors all events related to {@link MovieView}.
-     */
-    public static abstract class MovieListener {
+    /** Monitors all events related to {@link MovieView}. */
+    public abstract static class MovieListener {
 
-        /**
-         * Called when the video is started or resumed.
-         */
-        public void onMovieStarted() {
-        }
+        /** Called when the video is started or resumed. */
+        public void onMovieStarted() {}
 
-        /**
-         * Called when the video is paused or finished.
-         */
-        public void onMovieStopped() {
-        }
+        /** Called when the video is paused or finished. */
+        public void onMovieStopped() {}
 
-        /**
-         * Called when this view should be minimized.
-         */
-        public void onMovieMinimized() {
-        }
+        /** Called when this view should be minimized. */
+        public void onMovieMinimized() {}
     }
 
     private static final String TAG = "MovieView";
@@ -95,8 +83,7 @@
     MediaPlayer mMediaPlayer;
 
     /** The resource ID for the video to play. */
-    @RawRes
-    private int mVideoResourceId;
+    @RawRes private int mVideoResourceId;
 
     /** Whether we adjust our view bounds or we fill the remaining area with black bars */
     private boolean mAdjustViewBounds;
@@ -123,56 +110,61 @@
 
         // Inflate the content
         inflate(context, R.layout.view_movie, this);
-        mSurfaceView = (SurfaceView) findViewById(R.id.surface);
+        mSurfaceView = findViewById(R.id.surface);
         mShade = findViewById(R.id.shade);
-        mToggle = (ImageButton) findViewById(R.id.toggle);
-        mFastForward = (ImageButton) findViewById(R.id.fast_forward);
-        mFastRewind = (ImageButton) findViewById(R.id.fast_rewind);
-        mMinimize = (ImageButton) findViewById(R.id.minimize);
+        mToggle = findViewById(R.id.toggle);
+        mFastForward = findViewById(R.id.fast_forward);
+        mFastRewind = findViewById(R.id.fast_rewind);
+        mMinimize = findViewById(R.id.minimize);
 
         // Attributes
-        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MovieView,
-                defStyleAttr, R.style.Widget_PictureInPicture_MovieView);
+        final TypedArray a =
+                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();
 
         // Bind view events
-        final OnClickListener listener = new OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                switch (view.getId()) {
-                    case R.id.surface:
-                        toggleControls();
-                        break;
-                    case R.id.toggle:
-                        toggle();
-                        break;
-                    case R.id.fast_forward:
-                        fastForward();
-                        break;
-                    case R.id.fast_rewind:
-                        fastRewind();
-                        break;
-                    case R.id.minimize:
-                        if (mMovieListener != null) {
-                            mMovieListener.onMovieMinimized();
+        final OnClickListener listener =
+                new OnClickListener() {
+                    @Override
+                    public void onClick(View view) {
+                        switch (view.getId()) {
+                            case R.id.surface:
+                                toggleControls();
+                                break;
+                            case R.id.toggle:
+                                toggle();
+                                break;
+                            case R.id.fast_forward:
+                                fastForward();
+                                break;
+                            case R.id.fast_rewind:
+                                fastRewind();
+                                break;
+                            case R.id.minimize:
+                                if (mMovieListener != null) {
+                                    mMovieListener.onMovieMinimized();
+                                }
+                                break;
                         }
-                        break;
-                }
-                // Start or reset the timeout to hide controls
-                if (mMediaPlayer != null) {
-                    if (mTimeoutHandler == null) {
-                        mTimeoutHandler = new TimeoutHandler(MovieView.this);
+                        // Start or reset the timeout to hide controls
+                        if (mMediaPlayer != null) {
+                            if (mTimeoutHandler == null) {
+                                mTimeoutHandler = new TimeoutHandler(MovieView.this);
+                            }
+                            mTimeoutHandler.removeMessages(TimeoutHandler.MESSAGE_HIDE_CONTROLS);
+                            if (mMediaPlayer.isPlaying()) {
+                                mTimeoutHandler.sendEmptyMessageDelayed(
+                                        TimeoutHandler.MESSAGE_HIDE_CONTROLS, TIMEOUT_CONTROLS);
+                            }
+                        }
                     }
-                    mTimeoutHandler.removeMessages(TimeoutHandler.MESSAGE_HIDE_CONTROLS);
-                    if (mMediaPlayer.isPlaying()) {
-                        mTimeoutHandler.sendEmptyMessageDelayed(
-                                TimeoutHandler.MESSAGE_HIDE_CONTROLS, TIMEOUT_CONTROLS);
-                    }
-                }
-            }
-        };
+                };
         mSurfaceView.setOnClickListener(listener);
         mToggle.setOnClickListener(listener);
         mFastForward.setOnClickListener(listener);
@@ -180,25 +172,29 @@
         mMinimize.setOnClickListener(listener);
 
         // Prepare video playback
-        mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
-            @Override
-            public void surfaceCreated(SurfaceHolder holder) {
-                openVideo(holder.getSurface());
-            }
+        mSurfaceView
+                .getHolder()
+                .addCallback(
+                        new SurfaceHolder.Callback() {
+                            @Override
+                            public void surfaceCreated(SurfaceHolder holder) {
+                                openVideo(holder.getSurface());
+                            }
 
-            @Override
-            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-                // Do nothing
-            }
+                            @Override
+                            public void surfaceChanged(
+                                    SurfaceHolder holder, int format, int width, int height) {
+                                // Do nothing
+                            }
 
-            @Override
-            public void surfaceDestroyed(SurfaceHolder holder) {
-                if (mMediaPlayer != null) {
-                    mSavedCurrentPosition = mMediaPlayer.getCurrentPosition();
-                }
-                closeVideo();
-            }
-        });
+                            @Override
+                            public void surfaceDestroyed(SurfaceHolder holder) {
+                                if (mMediaPlayer != null) {
+                                    mSavedCurrentPosition = mMediaPlayer.getCurrentPosition();
+                                }
+                                closeVideo();
+                            }
+                        });
     }
 
     @Override
@@ -214,17 +210,21 @@
                 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
                 if (mAdjustViewBounds) {
                     if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
-                        super.onMeasure(widthMeasureSpec,
-                                MeasureSpec.makeMeasureSpec((int) (width * aspectRatio),
-                                        MeasureSpec.EXACTLY));
+                        super.onMeasure(
+                                widthMeasureSpec,
+                                MeasureSpec.makeMeasureSpec(
+                                        (int) (width * aspectRatio), MeasureSpec.EXACTLY));
                     } else if (widthMode != MeasureSpec.EXACTLY
                             && heightMode == MeasureSpec.EXACTLY) {
-                        super.onMeasure(MeasureSpec.makeMeasureSpec((int) (height / aspectRatio),
-                                MeasureSpec.EXACTLY), heightMeasureSpec);
+                        super.onMeasure(
+                                MeasureSpec.makeMeasureSpec(
+                                        (int) (height / aspectRatio), MeasureSpec.EXACTLY),
+                                heightMeasureSpec);
                     } else {
-                        super.onMeasure(widthMeasureSpec,
-                                MeasureSpec.makeMeasureSpec((int) (width * aspectRatio),
-                                        MeasureSpec.EXACTLY));
+                        super.onMeasure(
+                                widthMeasureSpec,
+                                MeasureSpec.makeMeasureSpec(
+                                        (int) (width * aspectRatio), MeasureSpec.EXACTLY));
                     }
                 } else {
                     final float viewRatio = (float) height / width;
@@ -262,6 +262,15 @@
     }
 
     /**
+     * The raw resource id of the video to play.
+     *
+     * @return ID of the video resource.
+     */
+    public int getVideoResourceId() {
+        return mVideoResourceId;
+    }
+
+    /**
      * Sets the raw resource ID of video to play.
      *
      * @param id The raw resource ID.
@@ -291,9 +300,7 @@
         requestLayout();
     }
 
-    /**
-     * Shows all the controls.
-     */
+    /** Shows all the controls. */
     public void showControls() {
         TransitionManager.beginDelayedTransition(this);
         mShade.setVisibility(View.VISIBLE);
@@ -303,9 +310,7 @@
         mMinimize.setVisibility(View.VISIBLE);
     }
 
-    /**
-     * Hides all the controls.
-     */
+    /** Hides all the controls. */
     public void hideControls() {
         TransitionManager.beginDelayedTransition(this);
         mShade.setVisibility(View.INVISIBLE);
@@ -315,9 +320,7 @@
         mMinimize.setVisibility(View.INVISIBLE);
     }
 
-    /**
-     * Fast-forward the video.
-     */
+    /** Fast-forward the video. */
     public void fastForward() {
         if (mMediaPlayer == null) {
             return;
@@ -325,9 +328,7 @@
         mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() + FAST_FORWARD_REWIND_INTERVAL);
     }
 
-    /**
-     * Fast-rewind the video.
-     */
+    /** Fast-rewind the video. */
     public void fastRewind() {
         if (mMediaPlayer == null) {
             return;
@@ -335,6 +336,19 @@
         mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() - FAST_FORWARD_REWIND_INTERVAL);
     }
 
+    /**
+     * Returns the current position of the video. If the the player has not been created, then
+     * assumes the beginning of the video.
+     *
+     * @return The current position of the video.
+     */
+    public int getCurrentPosition() {
+        if (mMediaPlayer == null) {
+            return 0;
+        }
+        return mMediaPlayer.getCurrentPosition();
+    }
+
     public boolean isPlaying() {
         return mMediaPlayer != null && mMediaPlayer.isPlaying();
     }
@@ -353,6 +367,7 @@
 
     public void pause() {
         if (mMediaPlayer == null) {
+            adjustToggleState();
             return;
         }
         mMediaPlayer.pause();
@@ -369,32 +384,40 @@
         }
         mMediaPlayer = new MediaPlayer();
         mMediaPlayer.setSurface(surface);
+        startVideo();
+    }
+
+    /** Restarts playback of the video. */
+    public void startVideo() {
+        mMediaPlayer.reset();
         try (AssetFileDescriptor fd = getResources().openRawResourceFd(mVideoResourceId)) {
             mMediaPlayer.setDataSource(fd);
-            mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
-                @Override
-                public void onPrepared(MediaPlayer mediaPlayer) {
-                    // Adjust the aspect ratio of this view
-                    requestLayout();
-                    if (mSavedCurrentPosition > 0) {
-                        mediaPlayer.seekTo(mSavedCurrentPosition);
-                        mSavedCurrentPosition = 0;
-                    } else {
-                        // Start automatically
-                        play();
-                    }
-                }
-            });
-            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
-                @Override
-                public void onCompletion(MediaPlayer mediaPlayer) {
-                    adjustToggleState();
-                    setKeepScreenOn(false);
-                    if (mMovieListener != null) {
-                        mMovieListener.onMovieStopped();
-                    }
-                }
-            });
+            mMediaPlayer.setOnPreparedListener(
+                    new MediaPlayer.OnPreparedListener() {
+                        @Override
+                        public void onPrepared(MediaPlayer mediaPlayer) {
+                            // Adjust the aspect ratio of this view
+                            requestLayout();
+                            if (mSavedCurrentPosition > 0) {
+                                mediaPlayer.seekTo(mSavedCurrentPosition);
+                                mSavedCurrentPosition = 0;
+                            } else {
+                                // Start automatically
+                                play();
+                            }
+                        }
+                    });
+            mMediaPlayer.setOnCompletionListener(
+                    new MediaPlayer.OnCompletionListener() {
+                        @Override
+                        public void onCompletion(MediaPlayer mediaPlayer) {
+                            adjustToggleState();
+                            setKeepScreenOn(false);
+                            if (mMovieListener != null) {
+                                mMovieListener.onMovieStopped();
+                            }
+                        }
+                    });
             mMediaPlayer.prepare();
         } catch (IOException e) {
             Log.e(TAG, "Failed to open video", e);
@@ -428,7 +451,7 @@
     }
 
     void adjustToggleState() {
-        if (mMediaPlayer == null || mMediaPlayer.isPlaying()) {
+        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
             mToggle.setContentDescription(getResources().getString(R.string.pause));
             mToggle.setImageResource(R.drawable.ic_pause_64dp);
         } else {
@@ -460,7 +483,5 @@
                     super.handleMessage(msg);
             }
         }
-
     }
-
 }
diff --git a/prebuilts/gradle/PictureInPicture/app/src/main/res/drawable/ic_picture_in_picture_alt.xml b/prebuilts/gradle/PictureInPicture/app/src/main/res/drawable/ic_picture_in_picture_alt.xml
index 941f21e..67f2ca6 100644
--- a/prebuilts/gradle/PictureInPicture/app/src/main/res/drawable/ic_picture_in_picture_alt.xml
+++ b/prebuilts/gradle/PictureInPicture/app/src/main/res/drawable/ic_picture_in_picture_alt.xml
@@ -12,11 +12,11 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
         android:pathData="M19,11h-8v6h8v-6zM23,19L23,4.98C23,3.88 22.1,3 21,3L3,3c-1.1,0 -2,0.88 -2,1.98L1,19c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2zM21,19.02L3,19.02L3,4.97h18v14.05z"
-        android:fillColor="#000000"/>
+        android:fillColor="#FFFFFFFF"/>
 </vector>
diff --git a/prebuilts/gradle/PictureInPicture/app/src/main/res/layout/activity_main.xml b/prebuilts/gradle/PictureInPicture/app/src/main/res/layout/activity_main.xml
index 4f1adc4..91487c8 100644
--- a/prebuilts/gradle/PictureInPicture/app/src/main/res/layout/activity_main.xml
+++ b/prebuilts/gradle/PictureInPicture/app/src/main/res/layout/activity_main.xml
@@ -60,6 +60,12 @@
                 android:text="@string/explanation"
                 android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
 
+            <Button
+                android:id="@+id/switch_example"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                tools:text="@string/switch_media_session"/>
+
         </LinearLayout>
 
     </ScrollView>
diff --git a/prebuilts/gradle/PictureInPicture/app/src/main/res/values/strings.xml b/prebuilts/gradle/PictureInPicture/app/src/main/res/values/strings.xml
index c790c84..5bcafe2 100644
--- a/prebuilts/gradle/PictureInPicture/app/src/main/res/values/strings.xml
+++ b/prebuilts/gradle/PictureInPicture/app/src/main/res/values/strings.xml
@@ -31,4 +31,6 @@
     Picture-in-Picture mode. On Picture-in-Picture screen, the app shows an action item to pause or
     resume the video.
     ]]></string>
+    <string name="switch_custom">Switch to custom actions example</string>
+    <string name="switch_media_session">Switch to using MediaSession</string>
 </resources>
diff --git a/prebuilts/gradle/PictureInPicture/app/src/main/res/values/styles.xml b/prebuilts/gradle/PictureInPicture/app/src/main/res/values/styles.xml
index 65747bc..d6a6d8d 100644
--- a/prebuilts/gradle/PictureInPicture/app/src/main/res/values/styles.xml
+++ b/prebuilts/gradle/PictureInPicture/app/src/main/res/values/styles.xml
@@ -29,9 +29,4 @@
         <item name="android:adjustViewBounds">false</item>
     </style>
 
-    <style name="ThemeOverlay.PictureInPicture.SeekBar" parent="ThemeOverlay.AppCompat">
-        <item name="colorAccent">@android:color/white</item>
-        <item name="colorControlNormal">@android:color/white</item>
-    </style>
-
 </resources>
diff --git a/prebuilts/gradle/PictureInPicture/build.gradle b/prebuilts/gradle/PictureInPicture/build.gradle
index 5b96c75..a642fa1 100644
--- a/prebuilts/gradle/PictureInPicture/build.gradle
+++ b/prebuilts/gradle/PictureInPicture/build.gradle
@@ -2,15 +2,21 @@
 
 buildscript {
     repositories {
+        maven {
+            url 'https://maven.google.com'
+        }
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.4.0-alpha6'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
 allprojects {
     repositories {
+        maven {
+            url 'https://maven.google.com'
+        }
         jcenter()
     }
 }
diff --git a/prebuilts/gradle/PictureInPicture/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/PictureInPicture/gradle/wrapper/gradle-wrapper.properties
index 1d9dc45..02e8c93 100644
--- a/prebuilts/gradle/PictureInPicture/gradle/wrapper/gradle-wrapper.properties
+++ b/prebuilts/gradle/PictureInPicture/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue May 16 19:45:19 PDT 2017
+#Mon Oct 02 16:19:57 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.1-all.zip
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/.google/packaging.yaml b/prebuilts/gradle/PictureInPicture/kotlinApp/.google/packaging.yaml
index 1858fec..ce1c438 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/.google/packaging.yaml
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/.google/packaging.yaml
@@ -5,14 +5,15 @@
 ---
 status:       PUBLISHED
 technologies: [Android]
-categories:   [Media, Android O Preview]
+categories:   [Media, Android Oreo]
 languages:    [Kotlin]
 solutions:    [Mobile]
 github:       android-PictureInPicture
 level:        ADVANCED
 icon:         screenshots/icon-web.png
 apiRefs:
-    - android:android.app.PictureInPictureArgs
+    - android:android.app.PictureInPictureParams
     - android:android.app.RemoteAction
     - android:android.app.PendingIntent
+    - android:android.support.v4.media.session.MediaSessionCompat
 license: apache2
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/README.md b/prebuilts/gradle/PictureInPicture/kotlinApp/README.md
index 9ff80ce..aa7f448 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/README.md
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/README.md
@@ -9,9 +9,8 @@
 Introduction
 ------------
 
-The O Developer Preview allows activities to launch in Picture-in-Picture (PiP) mode. PiP is a
-special type of [multi-window][1] mode mostly used for video playback. PiP mode is already available
-for [Android TV][2]; the O Developer Preview makes the feature available on other Android devices.
+As of Android O, activities can launch in [Picture-in-Picture (PiP)][1] mode. PiP is a
+special type of [multi-window][2] mode mostly used for video playback.
 
 The app is *paused* when it enters PiP mode, but it should continue showing content. For this
 reason, you should make sure your app does not pause playback in its [onPause()][3]
@@ -24,31 +23,31 @@
 other Android devices; you only need to `setrandroid:resizeableActivity` if your activity supports
 other multi-window modes.)
 
-You can pass a [PictureInPictureArgs][6] to [enterPictureInPictureMode()][7] to specify how an
+You can pass a [PictureInPictureParams][6] to [enterPictureInPictureMode()][7] to specify how an
 activity should behave when it is in PiP mode. You can also use it to call
-[setPictureInPictureArgs()][8] and update the current behavior. If the app is in not PiP mode, it
+[setPictureInPictureParams()][8] and update the current behavior. If the app is in not PiP mode, it
 will be used for later call of [enterPictureInPictureMode()][7].
 
-With a [PictureInPictureArgs][6], you can specify aspect ratio of PiP activity and action items
+With a [PictureInPictureParams][6], you can specify aspect ratio of PiP activity and action items
 available for PiP mode. The aspect ratio is used when the activity is in PiP mode. The action items
 are used as menu items in PiP mode. You can use a [PendingIntent][9] to specify what to do when the
 item is selected.
 
 [1]: https://developer.android.com/guide/topics/ui/multi-window.html
-[2]: https://developer.android.com/training/tv/playback/picture-in-picture.html
+[2]: https://developer.android.com/guide/topics/ui/picture-in-picture.html
 [3]: https://developer.android.com/reference/android/app/Activity.html#onPause()
 [4]: https://developer.android.com/reference/android/app/Activity.html#onStop()
 [5]: https://developer.android.com/guide/topics/ui/multi-window.html#lifecycle
-[6]: https://developer.android.com/reference/android/app/PictureInPictureArgs.html
-[7]: https://developer.android.com/reference/android/app/Activity.html#enterPictureInPictureMode(android.app.PictureInPictureArgs)
-[8]: https://developer.android.com/reference/android/app/Activity.html#setPictureInPictureArgs(android.app.PictureInPictureArgs)
+[6]: https://developer.android.com/reference/android/app/PictureInPictureParams.html
+[7]: https://developer.android.com/reference/android/app/Activity.html#enterPictureInPictureMode(android.app.PictureInPictureParams)
+[8]: https://developer.android.com/reference/android/app/Activity.html#setPictureInPictureParams(android.app.PictureInPictureParams)
 [9]: https://developer.android.com/reference/android/app/PendingIntent.html
 
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.2
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/build.gradle b/prebuilts/gradle/PictureInPicture/kotlinApp/app/build.gradle
index de4cc9e..acb53a2 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/app/build.gradle
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/build.gradle
@@ -2,7 +2,7 @@
     repositories {
         jcenter()
     }
-    ext.kotlin_version = '1.1.2-4'
+    ext.kotlin_version = '1.1.3-2'
     dependencies {
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
@@ -13,12 +13,12 @@
 apply plugin: 'kotlin-android-extensions'
 
 android {
-    compileSdkVersion 'android-O'
-    buildToolsVersion "25.0.2"
+    compileSdkVersion 26
+    buildToolsVersion "26.0.2"
     defaultConfig {
         applicationId "com.example.android.pictureinpicture"
-        minSdkVersion 'O'
-        targetSdkVersion 'O'
+        minSdkVersion 26
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -36,7 +36,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:25.3.1'
+    compile 'com.android.support:appcompat-v7:26.1.0'
+    compile 'com.android.support:support-media-compat:26.1.0'
 
     testCompile 'junit:junit:4.12'
     compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/androidTest/java/com/example/android/pictureinpicture/MainActivityTest.kt b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/androidTest/java/com/example/android/pictureinpicture/MainActivityTest.kt
index 377148a..282fa69 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/androidTest/java/com/example/android/pictureinpicture/MainActivityTest.kt
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/androidTest/java/com/example/android/pictureinpicture/MainActivityTest.kt
@@ -62,7 +62,7 @@
         rule.runOnUiThread {
             // We are now in Picture-in-Picture mode
             assertTrue(rule.activity.isInPictureInPictureMode)
-            val view = rule.activity.findViewById(R.id.movie) as MovieView
+            val view = rule.activity.findViewById<MovieView>(R.id.movie)
             assertNotNull(view)
             // The video should still be playing
             assertTrue(view.isPlaying)
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/androidTest/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivityTest.kt b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/androidTest/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivityTest.kt
new file mode 100644
index 0000000..88fb301
--- /dev/null
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/androidTest/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivityTest.kt
@@ -0,0 +1,171 @@
+/*
+ * 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.pictureinpicture
+
+import android.content.pm.ActivityInfo
+import android.support.test.InstrumentationRegistry
+import android.support.test.espresso.Espresso.onView
+import android.support.test.espresso.UiController
+import android.support.test.espresso.ViewAction
+import android.support.test.espresso.action.ViewActions.click
+import android.support.test.espresso.assertion.ViewAssertions.matches
+import android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom
+import android.support.test.espresso.matcher.ViewMatchers.isDisplayed
+import android.support.test.espresso.matcher.ViewMatchers.withId
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import android.support.v4.media.session.PlaybackStateCompat
+import android.view.View
+import com.example.android.pictureinpicture.widget.MovieView
+import org.hamcrest.Description
+import org.hamcrest.Matcher
+import org.hamcrest.Matchers.not
+import org.hamcrest.TypeSafeMatcher
+import org.hamcrest.core.AllOf.allOf
+import org.hamcrest.core.Is.`is`
+import org.hamcrest.core.IsEqual.equalTo
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertThat
+import org.junit.Assert.assertTrue
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+
+@RunWith(AndroidJUnit4::class)
+class MediaSessionPlaybackActivityTest {
+
+    @Rule @JvmField
+    val rule = ActivityTestRule(MediaSessionPlaybackActivity::class.java)
+
+    @Test
+    fun movie_playingOnPip() {
+        // The movie should be playing on start
+        onView(withId(R.id.movie))
+                .check(matches(allOf(isDisplayed(), isPlaying())))
+                .perform(showControls())
+        // Click on the button to enter Picture-in-Picture mode
+        onView(withId(R.id.minimize)).perform(click())
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+        // The Activity is paused. We cannot use Espresso to test paused activities.
+        rule.runOnUiThread {
+            // We are now in Picture-in-Picture mode
+            assertTrue(rule.activity.isInPictureInPictureMode)
+            val view = rule.activity.findViewById<MovieView>(R.id.movie)
+            assertNotNull(view)
+            // The video should still be playing
+            assertTrue(view.isPlaying)
+
+            // The media session state should be playing.
+            assertMediaStateIs(PlaybackStateCompat.STATE_PLAYING)
+        }
+    }
+
+    @Test
+    fun movie_pauseAndResume() {
+        // The movie should be playing on start
+        onView(withId(R.id.movie))
+                .check(matches(allOf(isDisplayed(), isPlaying())))
+                .perform(showControls())
+        // Pause
+        onView(withId(R.id.toggle)).perform(click())
+        onView(withId(R.id.movie)).check(matches(not(isPlaying())))
+        // The media session state should be paused.
+        assertMediaStateIs(PlaybackStateCompat.STATE_PAUSED)
+        // Resume
+        onView(withId(R.id.toggle)).perform(click())
+        onView(withId(R.id.movie)).check(matches(isPlaying()))
+        // The media session state should be playing.
+        assertMediaStateIs(PlaybackStateCompat.STATE_PLAYING)
+    }
+
+    @Test
+    fun fullscreen_enabledOnLandscape() {
+        rule.runOnUiThread { rule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE }
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+        rule.runOnUiThread {
+            val decorView = rule.activity.window.decorView
+            assertThat(decorView.systemUiVisibility,
+                    hasFlag(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN))
+        }
+    }
+
+    @Test
+    fun fullscreen_disabledOnPortrait() {
+        rule.runOnUiThread {
+            rule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+        }
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+        rule.runOnUiThread {
+            val decorView = rule.activity.window.decorView
+            assertThat(decorView.systemUiVisibility,
+                    not(hasFlag(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)))
+        }
+    }
+
+    private fun assertMediaStateIs(@PlaybackStateCompat.State expectedState: Int) {
+        val state = rule.activity.mediaController.playbackState
+        assertNotNull(state)
+        assertThat(
+                "MediaSession is not in the correct state",
+                state?.state,
+                `is`<Int>(equalTo<Int>(expectedState)))
+    }
+
+    private fun isPlaying(): Matcher<View> {
+        return object : TypeSafeMatcher<View>() {
+            override fun matchesSafely(view: View): Boolean {
+                return (view as MovieView).isPlaying
+            }
+
+            override fun describeTo(description: Description) {
+                description.appendText("MovieView is playing")
+            }
+        }
+    }
+
+    private fun showControls(): ViewAction {
+        return object : ViewAction {
+            override fun getConstraints(): Matcher<View> {
+                return isAssignableFrom(MovieView::class.java)
+            }
+
+            override fun getDescription(): String {
+                return "Show controls of MovieView"
+            }
+
+            override fun perform(uiController: UiController, view: View) {
+                uiController.loopMainThreadUntilIdle()
+                (view as MovieView).showControls()
+                uiController.loopMainThreadUntilIdle()
+            }
+        }
+    }
+
+    private fun hasFlag(flag: Int): Matcher<in Int> {
+        return object : TypeSafeMatcher<Int>() {
+            override fun matchesSafely(i: Int?): Boolean {
+                return i?.and(flag) == flag
+            }
+
+            override fun describeTo(description: Description) {
+                description.appendText("Flag integer contains " + flag)
+            }
+        }
+    }
+
+}
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/AndroidManifest.xml b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/AndroidManifest.xml
index f95bcc8..88928e4 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/AndroidManifest.xml
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/AndroidManifest.xml
@@ -34,6 +34,9 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".MediaSessionPlaybackActivity"
+            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+            android:supportsPictureInPicture="true" />
 
     </application>
 
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MainActivity.kt b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MainActivity.kt
index 9675515..d223fe8 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MainActivity.kt
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MainActivity.kt
@@ -17,7 +17,7 @@
 package com.example.android.pictureinpicture
 
 import android.app.PendingIntent
-import android.app.PictureInPictureArgs
+import android.app.PictureInPictureParams
 import android.app.RemoteAction
 import android.content.BroadcastReceiver
 import android.content.Context
@@ -29,7 +29,9 @@
 import android.os.Bundle
 import android.support.annotation.DrawableRes
 import android.support.v7.app.AppCompatActivity
+import android.util.Rational
 import android.view.View
+import android.widget.Button
 import android.widget.ScrollView
 import com.example.android.pictureinpicture.widget.MovieView
 import java.util.*
@@ -40,27 +42,61 @@
  */
 class MainActivity : AppCompatActivity() {
 
+    companion object {
+
+        /** Intent action for media controls from Picture-in-Picture mode.  */
+        private val ACTION_MEDIA_CONTROL = "media_control"
+
+        /** Intent extra for media controls from Picture-in-Picture mode.  */
+        private val EXTRA_CONTROL_TYPE = "control_type"
+
+        /** The request code for play action PendingIntent.  */
+        private val REQUEST_PLAY = 1
+
+        /** The request code for pause action PendingIntent.  */
+        private val REQUEST_PAUSE = 2
+
+        /** The request code for info action PendingIntent.  */
+        private val REQUEST_INFO = 3
+
+        /** The intent extra value for play action.  */
+        private val CONTROL_TYPE_PLAY = 1
+
+        /** The intent extra value for pause action.  */
+        private val CONTROL_TYPE_PAUSE = 2
+
+    }
+
     /** The arguments to be used for Picture-in-Picture mode.  */
-    private val mPictureInPictureArgs = PictureInPictureArgs()
+    private val mPictureInPictureParamsBuilder = PictureInPictureParams.Builder()
 
     /** This shows the video.  */
-    private var mMovieView: MovieView? = null
+    private lateinit var mMovieView: MovieView
 
     /** The bottom half of the screen; hidden on landscape  */
-    private var mScrollView: ScrollView? = null
+    private lateinit var mScrollView: ScrollView
 
     /** A [BroadcastReceiver] to receive action item events from Picture-in-Picture mode.  */
-    private var mReceiver: BroadcastReceiver? = null
+    private val mReceiver = object : BroadcastReceiver() {
+        override fun onReceive(context: Context, intent: Intent?) {
+            intent?.let { intent ->
+                if (intent.action != ACTION_MEDIA_CONTROL) {
+                    return
+                }
+
+                // This is where we are called back from Picture-in-Picture action items.
+                val controlType = intent.getIntExtra(EXTRA_CONTROL_TYPE, 0)
+                when (controlType) {
+                    CONTROL_TYPE_PLAY -> mMovieView.play()
+                    CONTROL_TYPE_PAUSE -> mMovieView.pause()
+                }
+            }
+        }
+    }
 
     private val labelPlay: String by lazy { getString(R.string.play) }
     private val labelPause: String by lazy { getString(R.string.pause) }
 
-    private val mOnClickListener = View.OnClickListener { view ->
-        when (view.id) {
-            R.id.pip -> minimize()
-        }
-    }
-
     /**
      * Callbacks from the [MovieView] showing the video playback.
      */
@@ -120,12 +156,12 @@
                         Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.info_uri))),
                         0)))
 
-        mPictureInPictureArgs.setActions(actions)
+        mPictureInPictureParamsBuilder.setActions(actions)
 
         // This is how you can update action items (or aspect ratio) for Picture-in-Picture mode.
         // Note this call can happen even when the app is not in PiP mode. In that case, the
         // arguments will be used for at the next call of #enterPictureInPictureMode.
-        setPictureInPictureArgs(mPictureInPictureArgs)
+        setPictureInPictureParams(mPictureInPictureParamsBuilder.build())
     }
 
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -133,25 +169,31 @@
         setContentView(R.layout.activity_main)
 
         // View references
-        mMovieView = findViewById(R.id.movie) as MovieView
-        mScrollView = findViewById(R.id.scroll) as ScrollView
+        mMovieView = findViewById<MovieView>(R.id.movie)
+        mScrollView = findViewById<ScrollView>(R.id.scroll)
+
+        val switchExampleButton = findViewById<Button>(R.id.switch_example)
+        switchExampleButton.text = getString(R.string.switch_media_session)
+        switchExampleButton.setOnClickListener(SwitchActivityOnClick())
 
         // Set up the video; it automatically starts.
-        mMovieView?.setMovieListener(mMovieListener)
-        findViewById(R.id.pip).setOnClickListener(mOnClickListener)
+        mMovieView.setMovieListener(mMovieListener)
+        findViewById<Button>(R.id.pip).setOnClickListener { minimize() }
     }
 
     override fun onStop() {
         // On entering Picture-in-Picture mode, onPause is called, but not onStop.
         // For this reason, this is the place where we should pause the video playback.
-        mMovieView?.pause()
+        mMovieView.pause()
         super.onStop()
     }
 
     override fun onRestart() {
         super.onRestart()
         // Show the video controls so the video can be easily resumed.
-        mMovieView?.showControls()
+        if (!isInPictureInPictureMode) {
+            mMovieView.showControls()
+        }
     }
 
     override fun onConfigurationChanged(newConfig: Configuration) {
@@ -166,33 +208,18 @@
         }
     }
 
-    override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean,
-                                               newConfig: Configuration) {
+    override fun onPictureInPictureModeChanged(
+            isInPictureInPictureMode: Boolean, newConfig: Configuration) {
         super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
         if (isInPictureInPictureMode) {
             // Starts receiving events from action items in PiP mode.
-            mReceiver = object : BroadcastReceiver() {
-                override fun onReceive(context: Context, intent: Intent?) {
-                    if (intent == null || ACTION_MEDIA_CONTROL != intent.action) {
-                        return
-                    }
-
-                    // This is where we are called back from Picture-in-Picture action items.
-                    val controlType = intent.getIntExtra(EXTRA_CONTROL_TYPE, 0)
-                    when (controlType) {
-                        CONTROL_TYPE_PLAY -> mMovieView?.play()
-                        CONTROL_TYPE_PAUSE -> mMovieView?.pause()
-                    }
-                }
-            }
             registerReceiver(mReceiver, IntentFilter(ACTION_MEDIA_CONTROL))
         } else {
             // We are out of PiP mode. We can stop receiving events from it.
             unregisterReceiver(mReceiver)
-            mReceiver = null
             // Show the video controls if the video is not playing
-            if (mMovieView != null && !mMovieView!!.isPlaying) {
-                mMovieView!!.showControls()
+            if (!mMovieView.isPlaying) {
+                mMovieView.showControls()
             }
         }
     }
@@ -201,15 +228,11 @@
      * Enters Picture-in-Picture mode.
      */
     internal fun minimize() {
-        if (mMovieView == null) {
-            return
-        }
         // Hide the controls in picture-in-picture mode.
-        mMovieView!!.hideControls()
+        mMovieView.hideControls()
         // Calculate the aspect ratio of the PiP screen.
-        val aspectRatio = mMovieView!!.width.toFloat() / mMovieView!!.height
-        mPictureInPictureArgs.setAspectRatio(aspectRatio)
-        enterPictureInPictureMode(mPictureInPictureArgs)
+        mPictureInPictureParamsBuilder.setAspectRatio(Rational(mMovieView.width, mMovieView.height))
+        enterPictureInPictureMode(mPictureInPictureParamsBuilder.build())
     }
 
     /**
@@ -226,37 +249,22 @@
                     View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
                     View.SYSTEM_UI_FLAG_FULLSCREEN or
                     View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
-            mScrollView?.visibility = View.GONE
-            mMovieView?.setAdjustViewBounds(false)
+            mScrollView.visibility = View.GONE
+            mMovieView.setAdjustViewBounds(false)
         } else {
             decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-            mScrollView?.visibility = View.VISIBLE
-            mMovieView?.setAdjustViewBounds(true)
+            mScrollView.visibility = View.VISIBLE
+            mMovieView.setAdjustViewBounds(true)
         }
     }
 
-    companion object {
-
-        /** Intent action for media controls from Picture-in-Picture mode.  */
-        private val ACTION_MEDIA_CONTROL = "media_control"
-
-        /** Intent extra for media controls from Picture-in-Picture mode.  */
-        private val EXTRA_CONTROL_TYPE = "control_type"
-
-        /** The request code for play action PendingIntent.  */
-        private val REQUEST_PLAY = 1
-
-        /** The request code for pause action PendingIntent.  */
-        private val REQUEST_PAUSE = 2
-
-        /** The request code for info action PendingIntent.  */
-        private val REQUEST_INFO = 3
-
-        /** The intent extra value for play action.  */
-        private val CONTROL_TYPE_PLAY = 1
-
-        /** The intent extra value for pause action.  */
-        private val CONTROL_TYPE_PAUSE = 2
+    /**
+     * Launches [MediaSessionPlaybackActivity] and closes this activity.
+     */
+    private inner class SwitchActivityOnClick : View.OnClickListener {
+        override fun onClick(view: View) {
+            startActivity(Intent(view.context, MediaSessionPlaybackActivity::class.java))
+            finish()
+        }
     }
-
 }
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.kt b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.kt
new file mode 100644
index 0000000..0027501
--- /dev/null
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/MediaSessionPlaybackActivity.kt
@@ -0,0 +1,316 @@
+/*
+ * 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.pictureinpicture
+
+import android.app.PictureInPictureParams
+import android.content.Intent
+import android.content.res.Configuration
+import android.os.Bundle
+import android.support.v4.media.session.MediaControllerCompat
+import android.support.v4.media.session.MediaSessionCompat
+import android.support.v4.media.session.PlaybackStateCompat
+import android.support.v7.app.AppCompatActivity
+import android.util.Rational
+import android.view.View
+import android.widget.Button
+import android.widget.ScrollView
+
+import com.example.android.pictureinpicture.widget.MovieView
+
+
+/**
+ * Demonstrates usage of Picture-in-Picture when using
+ * [android.support.v4.media.session.MediaSessionCompat].
+ */
+class MediaSessionPlaybackActivity : AppCompatActivity() {
+
+    companion object {
+
+        private val TAG = "MediaSessionPlaybackActivity"
+
+        val MEDIA_ACTIONS_PLAY_PAUSE =
+                PlaybackStateCompat.ACTION_PLAY or
+                        PlaybackStateCompat.ACTION_PAUSE or
+                        PlaybackStateCompat.ACTION_PLAY_PAUSE
+
+        val MEDIA_ACTIONS_ALL =
+                MEDIA_ACTIONS_PLAY_PAUSE or
+                        PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
+                        PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
+    }
+
+    private lateinit var mSession: MediaSessionCompat
+
+    /** The arguments to be used for Picture-in-Picture mode.  */
+    private val mPictureInPictureParamsBuilder = PictureInPictureParams.Builder()
+
+    /** This shows the video.  */
+    private lateinit var mMovieView: MovieView
+
+    /** The bottom half of the screen; hidden on landscape  */
+    private lateinit var mScrollView: ScrollView
+
+    private val mOnClickListener = View.OnClickListener { view ->
+        when (view.id) {
+            R.id.pip -> minimize()
+        }
+    }
+
+    /**
+     * Callbacks from the [MovieView] showing the video playback.
+     */
+    private val mMovieListener = object : MovieView.MovieListener() {
+
+        override fun onMovieStarted() {
+            // We are playing the video now. Update the media session state and the PiP window will
+            // update the actions.
+            mMovieView?.let { view ->
+                updatePlaybackState(
+                        PlaybackStateCompat.STATE_PLAYING,
+                        view.getCurrentPosition(),
+                        view.getVideoResourceId())
+            }
+        }
+
+        override fun onMovieStopped() {
+            // The video stopped or reached its end. Update the media session state and the PiP window will
+            // update the actions.
+            mMovieView?.let { view ->
+                updatePlaybackState(
+                        PlaybackStateCompat.STATE_PAUSED,
+                        view.getCurrentPosition(),
+                        view.getVideoResourceId())
+            }
+        }
+
+        override fun onMovieMinimized() {
+            // The MovieView wants us to minimize it. We enter Picture-in-Picture mode now.
+            minimize()
+        }
+
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+
+        // View references
+        mMovieView = findViewById<MovieView>(R.id.movie)
+        mScrollView = findViewById<ScrollView>(R.id.scroll)
+        val switchExampleButton = findViewById<Button>(R.id.switch_example)
+        switchExampleButton.text = getString(R.string.switch_custom)
+        switchExampleButton.setOnClickListener(SwitchActivityOnClick())
+
+        // Set up the video; it automatically starts.
+        mMovieView.setMovieListener(mMovieListener)
+        findViewById<View>(R.id.pip).setOnClickListener(mOnClickListener)
+    }
+
+    override fun onStart() {
+        super.onStart()
+        initializeMediaSession()
+    }
+
+    private fun initializeMediaSession() {
+        mSession = MediaSessionCompat(this, TAG)
+        mSession.setFlags(
+                MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
+        mSession.isActive = true
+        MediaControllerCompat.setMediaController(this, mSession.controller)
+
+        val mMediaSessionCallback = MediaSessionCallback(mMovieView)
+        mSession.setCallback(mMediaSessionCallback)
+
+        val state = if (mMovieView.isPlaying)
+            PlaybackStateCompat.STATE_PLAYING
+        else
+            PlaybackStateCompat.STATE_PAUSED
+        updatePlaybackState(
+                state,
+                MEDIA_ACTIONS_ALL,
+                mMovieView.getCurrentPosition(),
+                mMovieView.getVideoResourceId())
+    }
+
+    override fun onStop() {
+        super.onStop()
+        // On entering Picture-in-Picture mode, onPause is called, but not onStop.
+        // For this reason, this is the place where we should pause the video playback.
+        mMovieView.pause()
+        mSession.release()
+    }
+
+    override fun onRestart() {
+        super.onRestart()
+        if (!isInPictureInPictureMode) {
+            // Show the video controls so the video can be easily resumed.
+            mMovieView.showControls()
+        }
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        adjustFullScreen(newConfig)
+    }
+
+    override fun onWindowFocusChanged(hasFocus: Boolean) {
+        super.onWindowFocusChanged(hasFocus)
+        if (hasFocus) {
+            adjustFullScreen(resources.configuration)
+        }
+    }
+
+    override fun onPictureInPictureModeChanged(
+            isInPictureInPictureMode: Boolean, newConfig: Configuration) {
+        super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
+        if (!isInPictureInPictureMode) {
+            // Show the video controls if the video is not playing
+            if (!mMovieView.isPlaying) {
+                mMovieView.showControls()
+            }
+        }
+    }
+
+    /**
+     * Enters Picture-in-Picture mode.
+     */
+    internal fun minimize() {
+        // Hide the controls in picture-in-picture mode.
+        mMovieView.hideControls()
+        // Calculate the aspect ratio of the PiP screen.
+        val aspectRatio = Rational(mMovieView.width, mMovieView.height)
+        mPictureInPictureParamsBuilder.setAspectRatio(aspectRatio).build()
+        enterPictureInPictureMode(mPictureInPictureParamsBuilder.build())
+    }
+
+    /**
+     * Adjusts immersive full-screen flags depending on the screen orientation.
+
+     * @param config The current [Configuration].
+     */
+    private fun adjustFullScreen(config: Configuration) {
+        val decorView = window.decorView
+        if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+            mScrollView.visibility = View.GONE
+            mMovieView.setAdjustViewBounds(false)
+        } else {
+            decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+            mScrollView.visibility = View.VISIBLE
+            mMovieView.setAdjustViewBounds(true)
+        }
+    }
+
+    /**
+     * Overloaded method that persists previously set media actions.
+
+     * @param state The state of the video, e.g. playing, paused, etc.
+     * *
+     * @param position The position of playback in the video.
+     * *
+     * @param mediaId The media id related to the video in the media session.
+     */
+    private fun updatePlaybackState(
+            @PlaybackStateCompat.State state: Int,
+            position: Int,
+            mediaId: Int) {
+        val actions = mSession.controller.playbackState.actions
+        updatePlaybackState(state, actions, position, mediaId)
+    }
+
+    private fun updatePlaybackState(
+            @PlaybackStateCompat.State state: Int,
+            playbackActions: Long,
+            position: Int,
+            mediaId: Int) {
+        val builder = PlaybackStateCompat.Builder()
+                .setActions(playbackActions)
+                .setActiveQueueItemId(mediaId.toLong())
+                .setState(state, position.toLong(), 1.0f)
+        mSession.setPlaybackState(builder.build())
+    }
+
+    /**
+     * Updates the [MovieView] based on the callback actions. <br></br>
+     * Simulates a playlist that will disable actions when you cannot skip through the playlist in a
+     * certain direction.
+     */
+    private inner class MediaSessionCallback(private val movieView: MovieView) : MediaSessionCompat.Callback() {
+        private val PLAYLIST_SIZE = 2
+
+        private var indexInPlaylist: Int = 0
+
+        init {
+            indexInPlaylist = 1
+        }
+
+        override fun onPlay() {
+            super.onPlay()
+            movieView.play()
+        }
+
+        override fun onPause() {
+            super.onPause()
+            movieView.pause()
+        }
+
+        override fun onSkipToNext() {
+            super.onSkipToNext()
+            movieView.startVideo()
+            if( indexInPlaylist < PLAYLIST_SIZE ) {
+                indexInPlaylist++
+                if (indexInPlaylist >= PLAYLIST_SIZE) {
+                    updatePlaybackState(PlaybackStateCompat.STATE_PLAYING,
+                            MEDIA_ACTIONS_PLAY_PAUSE or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS,
+                            movieView.getCurrentPosition(),
+                            movieView.getVideoResourceId())
+                } else {
+                    updatePlaybackState(PlaybackStateCompat.STATE_PLAYING,
+                            MEDIA_ACTIONS_ALL,
+                            movieView.getCurrentPosition(),
+                            movieView.getVideoResourceId())
+                }
+            }
+        }
+
+        override fun onSkipToPrevious() {
+            super.onSkipToPrevious()
+            movieView.startVideo()
+            if( indexInPlaylist > 0 ) {
+                indexInPlaylist--
+                if (indexInPlaylist <= 0) {
+                    updatePlaybackState(PlaybackStateCompat.STATE_PLAYING,
+                            MEDIA_ACTIONS_PLAY_PAUSE or PlaybackStateCompat.ACTION_SKIP_TO_NEXT,
+                            movieView.getCurrentPosition(),
+                            movieView.getVideoResourceId())
+                } else {
+                    updatePlaybackState(PlaybackStateCompat.STATE_PLAYING,
+                            MEDIA_ACTIONS_ALL,
+                            movieView.getCurrentPosition(),
+                            movieView.getVideoResourceId())
+                }
+            }
+        }
+    }
+
+    private inner class SwitchActivityOnClick : View.OnClickListener {
+        override fun onClick(view: View) {
+            startActivity(Intent(view.context, MainActivity::class.java))
+            finish()
+        }
+    }
+}
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.kt b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.kt
index e204ff3..5d85f69 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.kt
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/java/com/example/android/pictureinpicture/widget/MovieView.kt
@@ -47,6 +47,18 @@
                                           defStyleAttr: Int = 0) :
         RelativeLayout(context, attrs, defStyleAttr) {
 
+    companion object {
+
+        private val TAG = "MovieView"
+
+        /** The amount of time we are stepping forward or backward for fast-forward and fast-rewind.  */
+        private val FAST_FORWARD_REWIND_INTERVAL = 5000 // ms
+
+        /** The amount of time until we fade out the controls.  */
+        private val TIMEOUT_CONTROLS = 3000L // ms
+
+    }
+
     /**
      * Monitors all events related to [MovieView].
      */
@@ -101,12 +113,12 @@
 
         // Inflate the content
         View.inflate(context, R.layout.view_movie, this)
-        mSurfaceView = findViewById<View>(R.id.surface) as SurfaceView
+        mSurfaceView = findViewById<SurfaceView>(R.id.surface)
         mShade = findViewById<View>(R.id.shade)
-        mToggle = findViewById<View>(R.id.toggle) as ImageButton
-        mFastForward = findViewById<View>(R.id.fast_forward) as ImageButton
-        mFastRewind = findViewById<View>(R.id.fast_rewind) as ImageButton
-        mMinimize = findViewById<View>(R.id.minimize) as ImageButton
+        mToggle = findViewById<ImageButton>(R.id.toggle)
+        mFastForward = findViewById<ImageButton>(R.id.fast_forward)
+        mFastRewind = findViewById<ImageButton>(R.id.fast_rewind)
+        mMinimize = findViewById<ImageButton>(R.id.minimize)
 
         // Attributes
         val a = context.obtainStyledAttributes(attrs, R.styleable.MovieView,
@@ -125,14 +137,16 @@
                 R.id.minimize -> mMovieListener?.onMovieMinimized()
             }
             // Start or reset the timeout to hide controls
-            if (mMediaPlayer != null) {
+            mMediaPlayer?.let { player ->
                 if (mTimeoutHandler == null) {
                     mTimeoutHandler = TimeoutHandler(this@MovieView)
                 }
-                mTimeoutHandler!!.removeMessages(TimeoutHandler.MESSAGE_HIDE_CONTROLS)
-                if (mMediaPlayer!!.isPlaying) {
-                    mTimeoutHandler!!.sendEmptyMessageDelayed(
-                            TimeoutHandler.MESSAGE_HIDE_CONTROLS, TIMEOUT_CONTROLS.toLong())
+                mTimeoutHandler?.let { handler ->
+                    handler.removeMessages(TimeoutHandler.MESSAGE_HIDE_CONTROLS)
+                    if (player.isPlaying) {
+                        handler.sendEmptyMessageDelayed(TimeoutHandler.MESSAGE_HIDE_CONTROLS,
+                                TIMEOUT_CONTROLS)
+                    }
                 }
             }
         }
@@ -148,23 +162,22 @@
                 openVideo(holder.surface)
             }
 
-            override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
+            override fun surfaceChanged(holder: SurfaceHolder, format: Int,
+                                        width: Int, height: Int) {
                 // Do nothing
             }
 
             override fun surfaceDestroyed(holder: SurfaceHolder) {
-                if (mMediaPlayer != null) {
-                    mSavedCurrentPosition = mMediaPlayer!!.currentPosition
-                }
+                mMediaPlayer?.let { mSavedCurrentPosition = it.currentPosition }
                 closeVideo()
             }
         })
     }
 
     override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
-        if (mMediaPlayer != null) {
-            val videoWidth = mMediaPlayer!!.videoWidth
-            val videoHeight = mMediaPlayer!!.videoHeight
+        mMediaPlayer?.let { player ->
+            val videoWidth = player.videoWidth
+            val videoHeight = player.videoHeight
             if (videoWidth != 0 && videoHeight != 0) {
                 val aspectRatio = videoHeight.toFloat() / videoWidth
                 val width = View.MeasureSpec.getSize(widthMeasureSpec)
@@ -172,11 +185,13 @@
                 val height = View.MeasureSpec.getSize(heightMeasureSpec)
                 val heightMode = View.MeasureSpec.getMode(heightMeasureSpec)
                 if (mAdjustViewBounds) {
-                    if (widthMode == View.MeasureSpec.EXACTLY && heightMode != View.MeasureSpec.EXACTLY) {
+                    if (widthMode == View.MeasureSpec.EXACTLY
+                            && heightMode != View.MeasureSpec.EXACTLY) {
                         super.onMeasure(widthMeasureSpec,
                                 View.MeasureSpec.makeMeasureSpec((width * aspectRatio).toInt(),
                                         View.MeasureSpec.EXACTLY))
-                    } else if (widthMode != View.MeasureSpec.EXACTLY && heightMode == View.MeasureSpec.EXACTLY) {
+                    } else if (widthMode != View.MeasureSpec.EXACTLY
+                            && heightMode == View.MeasureSpec.EXACTLY) {
                         super.onMeasure(View.MeasureSpec.makeMeasureSpec((height / aspectRatio).toInt(),
                                 View.MeasureSpec.EXACTLY), heightMeasureSpec)
                     } else {
@@ -202,14 +217,19 @@
     }
 
     override fun onDetachedFromWindow() {
-        if (mTimeoutHandler != null) {
-            mTimeoutHandler!!.removeMessages(TimeoutHandler.MESSAGE_HIDE_CONTROLS)
-            mTimeoutHandler = null
-        }
+        mTimeoutHandler?.removeMessages(TimeoutHandler.MESSAGE_HIDE_CONTROLS)
+        mTimeoutHandler = null
         super.onDetachedFromWindow()
     }
 
     /**
+     * The raw resource id of the video to play.
+
+     * @return ID of the video resource.
+     */
+    fun getVideoResourceId(): Int = mVideoResourceId
+
+    /**
      * Sets the listener to monitor movie events.
 
      * @param movieListener The listener to be set.
@@ -276,24 +296,26 @@
      * Fast-forward the video.
      */
     fun fastForward() {
-        if (mMediaPlayer == null) {
-            return
-        }
-        mMediaPlayer!!.seekTo(mMediaPlayer!!.currentPosition + FAST_FORWARD_REWIND_INTERVAL)
+        mMediaPlayer?.let { it.seekTo(it.currentPosition + FAST_FORWARD_REWIND_INTERVAL) }
     }
 
     /**
      * Fast-rewind the video.
      */
     fun fastRewind() {
-        if (mMediaPlayer == null) {
-            return
-        }
-        mMediaPlayer!!.seekTo(mMediaPlayer!!.currentPosition - FAST_FORWARD_REWIND_INTERVAL)
+        mMediaPlayer?.let { it.seekTo(it.currentPosition - FAST_FORWARD_REWIND_INTERVAL) }
     }
 
+    /**
+     * Returns the current position of the video. If the the player has not been created, then
+     * assumes the beginning of the video.
+
+     * @return The current position of the video.
+     */
+    fun getCurrentPosition(): Int = mMediaPlayer?.currentPosition ?: 0
+
     val isPlaying: Boolean
-        get() = mMediaPlayer != null && mMediaPlayer!!.isPlaying
+        get() = mMediaPlayer?.isPlaying ?: false
 
     fun play() {
         if (mMediaPlayer == null) {
@@ -302,21 +324,18 @@
         mMediaPlayer!!.start()
         adjustToggleState()
         keepScreenOn = true
-        if (mMovieListener != null) {
-            mMovieListener!!.onMovieStarted()
-        }
+        mMovieListener?.onMovieStarted()
     }
 
     fun pause() {
         if (mMediaPlayer == null) {
+            adjustToggleState()
             return
         }
         mMediaPlayer!!.pause()
         adjustToggleState()
         keepScreenOn = false
-        if (mMovieListener != null) {
-            mMovieListener!!.onMovieStopped()
-        }
+        mMovieListener?.onMovieStopped()
     }
 
     internal fun openVideo(surface: Surface) {
@@ -324,52 +343,52 @@
             return
         }
         mMediaPlayer = MediaPlayer()
-        mMediaPlayer!!.setSurface(surface)
-        try {
-            resources.openRawResourceFd(mVideoResourceId).use { fd ->
-                mMediaPlayer!!.setDataSource(fd)
-                mMediaPlayer!!.setOnPreparedListener { mediaPlayer ->
-                    // Adjust the aspect ratio of this view
-                    requestLayout()
-                    if (mSavedCurrentPosition > 0) {
-                        mediaPlayer.seekTo(mSavedCurrentPosition)
-                        mSavedCurrentPosition = 0
-                    } else {
-                        // Start automatically
-                        play()
-                    }
-                }
-                mMediaPlayer!!.setOnCompletionListener {
-                    adjustToggleState()
-                    keepScreenOn = false
-                    if (mMovieListener != null) {
-                        mMovieListener!!.onMovieStopped()
-                    }
-                }
-                mMediaPlayer!!.prepare()
-            }
-        } catch (e: IOException) {
-            Log.e(TAG, "Failed to open video", e)
+        mMediaPlayer?.let { player ->
+            player.setSurface(surface)
+            startVideo()
         }
+    }
 
+    /**
+     * Restarts playback of the video.
+     */
+    public fun startVideo() {
+        mMediaPlayer?.let { player ->
+            player.reset()
+            try {
+                resources.openRawResourceFd(mVideoResourceId).use { fd ->
+                    player.setDataSource(fd)
+                    player.setOnPreparedListener { mediaPlayer ->
+                        // Adjust the aspect ratio of this view
+                        requestLayout()
+                        if (mSavedCurrentPosition > 0) {
+                            mediaPlayer.seekTo(mSavedCurrentPosition)
+                            mSavedCurrentPosition = 0
+                        } else {
+                            // Start automatically
+                            play()
+                        }
+                    }
+                    player.setOnCompletionListener {
+                        adjustToggleState()
+                        keepScreenOn = false
+                        mMovieListener?.onMovieStopped()
+                    }
+                    player.prepare()
+                }
+            } catch (e: IOException) {
+                Log.e(TAG, "Failed to open video", e)
+            }
+        }
     }
 
     internal fun closeVideo() {
-        if (mMediaPlayer != null) {
-            mMediaPlayer!!.release()
-            mMediaPlayer = null
-        }
+        mMediaPlayer?.release()
+        mMediaPlayer = null
     }
 
     internal fun toggle() {
-        if (mMediaPlayer == null) {
-            return
-        }
-        if (mMediaPlayer!!.isPlaying) {
-            pause()
-        } else {
-            play()
-        }
+        mMediaPlayer?.let { if (it.isPlaying) pause() else play() }
     }
 
     internal fun toggleControls() {
@@ -381,24 +400,25 @@
     }
 
     internal fun adjustToggleState() {
-        if (mMediaPlayer == null || mMediaPlayer!!.isPlaying) {
-            mToggle.contentDescription = resources.getString(R.string.pause)
-            mToggle.setImageResource(R.drawable.ic_pause_64dp)
-        } else {
-            mToggle.contentDescription = resources.getString(R.string.play)
-            mToggle.setImageResource(R.drawable.ic_play_arrow_64dp)
+        mMediaPlayer?.let {
+            if (it.isPlaying) {
+                mToggle.contentDescription = resources.getString(R.string.pause)
+                mToggle.setImageResource(R.drawable.ic_pause_64dp)
+            } else {
+                mToggle.contentDescription = resources.getString(R.string.play)
+                mToggle.setImageResource(R.drawable.ic_play_arrow_64dp)
+            }
         }
     }
 
-    private class TimeoutHandler internal constructor(view: MovieView) : Handler() {
+    private class TimeoutHandler(view: MovieView) : Handler() {
 
         private val mMovieViewRef: WeakReference<MovieView> = WeakReference(view)
 
         override fun handleMessage(msg: Message) {
             when (msg.what) {
                 MESSAGE_HIDE_CONTROLS -> {
-                    val movieView = mMovieViewRef.get()
-                    movieView?.hideControls()
+                    mMovieViewRef.get()?.hideControls()
                 }
                 else -> super.handleMessage(msg)
             }
@@ -410,16 +430,4 @@
 
     }
 
-    companion object {
-
-        private val TAG = "MovieView"
-
-        /** The amount of time we are stepping forward or backward for fast-forward and fast-rewind.  */
-        private val FAST_FORWARD_REWIND_INTERVAL = 5000 // ms
-
-        /** The amount of time until we fade out the controls.  */
-        private val TIMEOUT_CONTROLS = 3000 // ms
-
-    }
-
 }
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/drawable/ic_picture_in_picture_alt.xml b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/drawable/ic_picture_in_picture_alt.xml
index 941f21e..67f2ca6 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/drawable/ic_picture_in_picture_alt.xml
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/drawable/ic_picture_in_picture_alt.xml
@@ -12,11 +12,11 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
         android:pathData="M19,11h-8v6h8v-6zM23,19L23,4.98C23,3.88 22.1,3 21,3L3,3c-1.1,0 -2,0.88 -2,1.98L1,19c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2zM21,19.02L3,19.02L3,4.97h18v14.05z"
-        android:fillColor="#000000"/>
+        android:fillColor="#FFFFFFFF"/>
 </vector>
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/layout/activity_main.xml b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/layout/activity_main.xml
index 4f1adc4..91487c8 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/layout/activity_main.xml
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/layout/activity_main.xml
@@ -60,6 +60,12 @@
                 android:text="@string/explanation"
                 android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
 
+            <Button
+                android:id="@+id/switch_example"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                tools:text="@string/switch_media_session"/>
+
         </LinearLayout>
 
     </ScrollView>
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/values/strings.xml b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/values/strings.xml
index c790c84..5bcafe2 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/values/strings.xml
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/values/strings.xml
@@ -31,4 +31,6 @@
     Picture-in-Picture mode. On Picture-in-Picture screen, the app shows an action item to pause or
     resume the video.
     ]]></string>
+    <string name="switch_custom">Switch to custom actions example</string>
+    <string name="switch_media_session">Switch to using MediaSession</string>
 </resources>
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/values/styles.xml b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/values/styles.xml
index 65747bc..d6a6d8d 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/values/styles.xml
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/app/src/main/res/values/styles.xml
@@ -29,9 +29,4 @@
         <item name="android:adjustViewBounds">false</item>
     </style>
 
-    <style name="ThemeOverlay.PictureInPicture.SeekBar" parent="ThemeOverlay.AppCompat">
-        <item name="colorAccent">@android:color/white</item>
-        <item name="colorControlNormal">@android:color/white</item>
-    </style>
-
 </resources>
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/build.gradle b/prebuilts/gradle/PictureInPicture/kotlinApp/build.gradle
index 3d80b5b..c8d330b 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/build.gradle
+++ b/prebuilts/gradle/PictureInPicture/kotlinApp/build.gradle
@@ -2,15 +2,21 @@
 
 buildscript {
     repositories {
+        maven {
+            url 'https://maven.google.com'
+        }
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.4.0-alpha6'
+        classpath 'com.android.tools.build:gradle:3.0.0-beta7'
     }
 }
 
 allprojects {
     repositories {
+        maven {
+            url 'https://maven.google.com'
+        }
         jcenter()
     }
 }
diff --git a/prebuilts/gradle/PictureInPicture/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/PictureInPicture/kotlinApp/gradle/wrapper/gradle-wrapper.properties
index 1d9dc45..8b227ef 100644
--- a/prebuilts/gradle/PictureInPicture/kotlinApp/gradle/wrapper/gradle-wrapper.properties
+++ b/prebuilts/gradle/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-3.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/prebuilts/gradle/PictureInPicture/screenshots/1-main.png b/prebuilts/gradle/PictureInPicture/screenshots/1-main.png
index b626998..1f2b770 100644
--- a/prebuilts/gradle/PictureInPicture/screenshots/1-main.png
+++ b/prebuilts/gradle/PictureInPicture/screenshots/1-main.png
Binary files differ
diff --git a/prebuilts/gradle/PictureInPicture/screenshots/2-pip.png b/prebuilts/gradle/PictureInPicture/screenshots/2-pip.png
index 1a8f096..ae428c7 100644
--- a/prebuilts/gradle/PictureInPicture/screenshots/2-pip.png
+++ b/prebuilts/gradle/PictureInPicture/screenshots/2-pip.png
Binary files differ
diff --git a/prebuilts/gradle/Quiz/Application/build.gradle b/prebuilts/gradle/Quiz/Application/build.gradle
index 49b1770..ddfdc08 100644
--- a/prebuilts/gradle/Quiz/Application/build.gradle
+++ b/prebuilts/gradle/Quiz/Application/build.gradle
@@ -19,12 +19,12 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.android.support:support-v13:25.3.1'
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     wearApp project(':Wearable')
 }
 
@@ -38,9 +38,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/Quiz/README.md b/prebuilts/gradle/Quiz/README.md
index 5dd6190..cac8db6 100644
--- a/prebuilts/gradle/Quiz/README.md
+++ b/prebuilts/gradle/Quiz/README.md
@@ -13,8 +13,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/Quiz/Wearable/build.gradle b/prebuilts/gradle/Quiz/Wearable/build.gradle
index e00b0d4..4e2a9d9 100644
--- a/prebuilts/gradle/Quiz/Wearable/build.gradle
+++ b/prebuilts/gradle/Quiz/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/RecipeAssistant/Application/build.gradle b/prebuilts/gradle/RecipeAssistant/Application/build.gradle
index 312518e..88ce6ad 100644
--- a/prebuilts/gradle/RecipeAssistant/Application/build.gradle
+++ b/prebuilts/gradle/RecipeAssistant/Application/build.gradle
@@ -19,10 +19,10 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -35,9 +35,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/RecipeAssistant/README.md b/prebuilts/gradle/RecipeAssistant/README.md
index 36f14e2..96af570 100644
--- a/prebuilts/gradle/RecipeAssistant/README.md
+++ b/prebuilts/gradle/RecipeAssistant/README.md
@@ -12,8 +12,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/RecyclerView/Application/build.gradle b/prebuilts/gradle/RecyclerView/Application/build.gradle
index 92b5a7b..c20f49f 100644
--- a/prebuilts/gradle/RecyclerView/Application/build.gradle
+++ b/prebuilts/gradle/RecyclerView/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.android.support:recyclerview-v7:24.0.0'
 }
 
@@ -32,12 +35,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/RecyclerView/README.md b/prebuilts/gradle/RecyclerView/README.md
index c7d5678..c510491 100644
--- a/prebuilts/gradle/RecyclerView/README.md
+++ b/prebuilts/gradle/RecyclerView/README.md
@@ -29,8 +29,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/RenderScriptIntrinsic/Application/build.gradle b/prebuilts/gradle/RenderScriptIntrinsic/Application/build.gradle
index 91a2bcb..4ceb79c 100644
--- a/prebuilts/gradle/RenderScriptIntrinsic/Application/build.gradle
+++ b/prebuilts/gradle/RenderScriptIntrinsic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile files('renderscript-v8.jar')
 }
 
@@ -32,12 +35,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 14
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/RenderScriptIntrinsic/README.md b/prebuilts/gradle/RenderScriptIntrinsic/README.md
index a7e5cf9..97b22cb 100644
--- a/prebuilts/gradle/RenderScriptIntrinsic/README.md
+++ b/prebuilts/gradle/RenderScriptIntrinsic/README.md
@@ -37,8 +37,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/RepeatingAlarm/Application/build.gradle b/prebuilts/gradle/RepeatingAlarm/Application/build.gradle
index 3c9428a..271193c 100644
--- a/prebuilts/gradle/RepeatingAlarm/Application/build.gradle
+++ b/prebuilts/gradle/RepeatingAlarm/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 11
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/RepeatingAlarm/README.md b/prebuilts/gradle/RepeatingAlarm/README.md
index ac3152e..5cf8467 100644
--- a/prebuilts/gradle/RepeatingAlarm/README.md
+++ b/prebuilts/gradle/RepeatingAlarm/README.md
@@ -8,8 +8,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/RevealEffectBasic/Application/build.gradle b/prebuilts/gradle/RevealEffectBasic/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/RevealEffectBasic/Application/build.gradle
+++ b/prebuilts/gradle/RevealEffectBasic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/RevealEffectBasic/README.md b/prebuilts/gradle/RevealEffectBasic/README.md
index 573132f..eef34ac 100644
--- a/prebuilts/gradle/RevealEffectBasic/README.md
+++ b/prebuilts/gradle/RevealEffectBasic/README.md
@@ -27,8 +27,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/RuntimePermissions/Application/build.gradle b/prebuilts/gradle/RuntimePermissions/Application/build.gradle
deleted file mode 100644
index 663260f..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/build.gradle
+++ /dev/null
@@ -1,61 +0,0 @@
-
-buildscript {
-    repositories {
-        jcenter()
-    }
-
-    dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
-    }
-}
-
-apply plugin: 'com.android.application'
-
-repositories {
-    jcenter()
-}
-
-dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
-    compile 'com.android.support:support-v4:24.0.0'
-    compile 'com.android.support:design:24.0.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 25
-    buildToolsVersion "25.0.3"
-
-    defaultConfig {
-        minSdkVersion 15
-        targetSdkVersion 25
-    }
-
-    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/prebuilts/gradle/RuntimePermissions/Application/src/main/AndroidManifest.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/AndroidManifest.xml
index 0acbb93..0fdb1d9 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/AndroidManifest.xml
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/AndroidManifest.xml
@@ -15,18 +15,18 @@
   limitations under the License.
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.system.runtimepermissions" >
+          package="com.example.android.system.runtimepermissions">
 
     <!-- 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"/>
+    <uses-permission android:name="android.permission.CAMERA" />
 
     <!-- The following permissions are only requested if the device is on M or above.
      On older platforms these permissions are not requested and will not be available. -->
-    <uses-permission-sdk-m android:name="android.permission.READ_CONTACTS" />
-    <uses-permission-sdk-m android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" />
+    <uses-permission-sdk-23 android:name="android.permission.WRITE_CONTACTS" />
 
     <!-- END_INCLUDE(manifest) -->
 
@@ -34,10 +34,11 @@
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
-        android:theme="@style/Theme.AppCompat.Light" >
+        android:supportsRtl="true"
+        android:theme="@style/Theme.AppCompat.Light">
         <activity
             android:name=".MainActivity"
-            android:label="@string/app_name" >
+            android:label="@string/app_name">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/Log.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/Log.java
deleted file mode 100644
index 17503c5..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/Log.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-package com.example.android.common.logger;
-
-/**
- * Helper class for a list (or tree) of LoggerNodes.
- *
- * <p>When this is set as the head of the list,
- * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
- * Most of the methods in this class server only to map a method call in Log to its equivalent
- * in LogNode.</p>
- */
-public class Log {
-    // Grabbing the native values from Android's native logging facilities,
-    // to make for easy migration and interop.
-    public static final int NONE = -1;
-    public static final int VERBOSE = android.util.Log.VERBOSE;
-    public static final int DEBUG = android.util.Log.DEBUG;
-    public static final int INFO = android.util.Log.INFO;
-    public static final int WARN = android.util.Log.WARN;
-    public static final int ERROR = android.util.Log.ERROR;
-    public static final int ASSERT = android.util.Log.ASSERT;
-
-    // Stores the beginning of the LogNode topology.
-    private static LogNode mLogNode;
-
-    /**
-     * Returns the next LogNode in the linked list.
-     */
-    public static LogNode getLogNode() {
-        return mLogNode;
-    }
-
-    /**
-     * Sets the LogNode data will be sent to.
-     */
-    public static void setLogNode(LogNode node) {
-        mLogNode = node;
-    }
-
-    /**
-     * 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.
-     */
-    public static void println(int priority, String tag, String msg, Throwable tr) {
-        if (mLogNode != null) {
-            mLogNode.println(priority, tag, msg, tr);
-        }
-    }
-
-    /**
-     * 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.
-     */
-    public static void println(int priority, String tag, String msg) {
-        println(priority, tag, msg, null);
-    }
-
-   /**
-     * 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.
-     */
-    public static void v(String tag, String msg, Throwable tr) {
-        println(VERBOSE, 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.
-     */
-    public static void v(String tag, String msg) {
-        v(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.
-     * @param tr If an exception was thrown, this can be sent along for the logging facilities
-     *           to extract and print useful information.
-     */
-    public static void d(String tag, String msg, Throwable tr) {
-        println(DEBUG, 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.
-     */
-    public static void d(String tag, String msg) {
-        d(tag, msg, null);
-    }
-
-    /**
-     * 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.
-     */
-    public static void i(String tag, String msg, Throwable tr) {
-        println(INFO, 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.
-     */
-    public static void i(String tag, String msg) {
-        i(tag, msg, null);
-    }
-
-    /**
-     * 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.
-     */
-    public static void w(String tag, String msg, Throwable tr) {
-        println(WARN, 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.
-     */
-    public static void w(String tag, String msg) {
-        w(tag, msg, null);
-    }
-
-    /**
-     * Prints a message at WARN priority.
-     *
-     * @param tag Tag for for the log data. Can be used to organize log statements.
-     * @param tr If an exception was thrown, this can be sent along for the logging facilities
-     *           to extract and print useful information.
-     */
-    public static void w(String tag, Throwable tr) {
-        w(tag, null, 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.
-     */
-    public static void e(String tag, String msg, Throwable tr) {
-        println(ERROR, 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.
-     */
-    public static void e(String tag, String msg) {
-        e(tag, msg, null);
-    }
-
-    /**
-     * 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.
-     */
-    public static void wtf(String tag, String msg, Throwable tr) {
-        println(ASSERT, 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.
-     */
-    public static void wtf(String tag, String msg) {
-        wtf(tag, msg, null);
-    }
-
-    /**
-     * Prints a message at ASSERT priority.
-     *
-     * @param tag Tag for for the log data. Can be used to organize log statements.
-     * @param tr If an exception was thrown, this can be sent along for the logging facilities
-     *           to extract and print useful information.
-     */
-    public static void wtf(String tag, Throwable tr) {
-        wtf(tag, null, tr);
-    }
-}
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogFragment.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogFragment.java
deleted file mode 100644
index b302acd..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogFragment.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-* 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.
-*/
-/*
- * 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.
- */
-
-package com.example.android.common.logger;
-
-import android.graphics.Typeface;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-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 fraggment which contains a LogView and uses is to output log data it receives
- * through the LogNode interface.
- */
-public class LogFragment extends Fragment {
-
-    private LogView mLogView;
-    private ScrollView mScrollView;
-
-    public LogFragment() {}
-
-    public View inflateViews() {
-        mScrollView = new ScrollView(getActivity());
-        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT);
-        mScrollView.setLayoutParams(scrollParams);
-
-        mLogView = new LogView(getActivity());
-        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
-        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-        mLogView.setLayoutParams(logParams);
-        mLogView.setClickable(true);
-        mLogView.setFocusable(true);
-        mLogView.setTypeface(Typeface.MONOSPACE);
-
-        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
-        int paddingDips = 16;
-        double scale = getResources().getDisplayMetrics().density;
-        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
-        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
-        mLogView.setCompoundDrawablePadding(paddingPixels);
-
-        mLogView.setGravity(Gravity.BOTTOM);
-        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
-
-        mScrollView.addView(mLogView);
-        return mScrollView;
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-                             Bundle savedInstanceState) {
-
-        View result = inflateViews();
-
-        mLogView.addTextChangedListener(new TextWatcher() {
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before, int count) {}
-
-            @Override
-            public void afterTextChanged(Editable s) {
-                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
-            }
-        });
-        return result;
-    }
-
-    public LogView getLogView() {
-        return mLogView;
-    }
-}
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogNode.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogNode.java
deleted file mode 100644
index bc37cab..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogNode.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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;
-
-/**
- * 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.
- */
-public 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.
-     */
-    public void println(int priority, String tag, String msg, Throwable tr);
-
-}
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogView.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogView.java
deleted file mode 100644
index c01542b..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogView.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-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.
-*/
-public class LogView extends TextView implements LogNode {
-
-    public LogView(Context context) {
-        super(context);
-    }
-
-    public LogView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public LogView(Context context, AttributeSet attrs, int defStyle) {
-        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
-    public void println(int priority, String tag, String msg, Throwable tr) {
-
-        
-        String priorityStr = null;
-
-        // For the purposes of this View, we want to print the priority as readable text.
-        switch(priority) {
-            case android.util.Log.VERBOSE:
-                priorityStr = "VERBOSE";
-                break;
-            case android.util.Log.DEBUG:
-                priorityStr = "DEBUG";
-                break;
-            case android.util.Log.INFO:
-                priorityStr = "INFO";
-                break;
-            case android.util.Log.WARN:
-                priorityStr = "WARN";
-                break;
-            case android.util.Log.ERROR:
-                priorityStr = "ERROR";
-                break;
-            case android.util.Log.ASSERT:
-                priorityStr = "ASSERT";
-                break;
-            default:
-                break;
-        }
-
-        // Handily, the Log class has a facility for converting a stack trace into a usable string.
-        String exceptionStr = 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.
-        final StringBuilder outputBuilder = new StringBuilder();
-
-        String 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.
-        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
-            @Override
-            public void run() {
-                // Display the text we just generated within the LogView.
-                appendToLog(outputBuilder.toString());
-            }
-        })));
-
-        if (mNext != null) {
-            mNext.println(priority, tag, msg, tr);
-        }
-    }
-
-    public LogNode getNext() {
-        return mNext;
-    }
-
-    public void setNext(LogNode node) {
-        mNext = node;
-    }
-
-    /** 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 StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
-        if (addStr != null) {
-            if (addStr.length() == 0) {
-                delimiter = "";
-            }
-
-            return source.append(addStr).append(delimiter);
-        }
-        return source;
-    }
-
-    // The next LogNode in the chain.
-    LogNode mNext;
-
-    /** Outputs the string as a new line of log data in the LogView. */
-    public void appendToLog(String s) {
-        append("\n" + s);
-    }
-
-
-}
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogWrapper.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogWrapper.java
deleted file mode 100644
index 16a9e7b..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/LogWrapper.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-public class LogWrapper implements LogNode {
-
-    // For piping:  The next node to receive Log data after this one has done its work.
-    private LogNode mNext;
-
-    /**
-     * Returns the next LogNode in the linked list.
-     */
-    public LogNode getNext() {
-        return mNext;
-    }
-
-    /**
-     * Sets the LogNode data will be sent to..
-     */
-    public void setNext(LogNode node) {
-        mNext = node;
-    }
-
-    /**
-     * 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
-    public void println(int priority, String tag, String msg, Throwable tr) {
-        // 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.
-        String useMsg = msg;
-        if (useMsg == null) {
-            useMsg = "";
-        }
-
-        // If an exeption 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.
-        if (mNext != null) {
-            mNext.println(priority, tag, msg, tr);
-        }
-    }
-}
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java
deleted file mode 100644
index 19967dc..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-package com.example.android.common.logger;
-
-/**
- * Simple {@link 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.
- */
-public class MessageOnlyLogFilter implements LogNode {
-
-    LogNode mNext;
-
-    /**
-     * Takes the "next" LogNode as a parameter, to simplify chaining.
-     *
-     * @param next The next LogNode in the pipeline.
-     */
-    public MessageOnlyLogFilter(LogNode next) {
-        mNext = next;
-    }
-
-    public MessageOnlyLogFilter() {
-    }
-
-    @Override
-    public void println(int priority, String tag, String msg, Throwable tr) {
-        if (mNext != null) {
-            getNext().println(Log.NONE, null, msg, null);
-        }
-    }
-
-    /**
-     * Returns the next LogNode in the chain.
-     */
-    public LogNode getNext() {
-        return mNext;
-    }
-
-    /**
-     * Sets the LogNode data will be sent to..
-     */
-    public void setNext(LogNode node) {
-        mNext = node;
-    }
-
-}
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/MainActivity.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/MainActivity.java
index 7abc538..37db139 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/MainActivity.java
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/MainActivity.java
@@ -16,13 +16,6 @@
 
 package com.example.android.system.runtimepermissions;
 
-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;
-import com.example.android.system.runtimepermissions.camera.CameraPreviewFragment;
-import com.example.android.system.runtimepermissions.contacts.ContactsFragment;
-
 import android.Manifest;
 import android.app.Activity;
 import android.content.Context;
@@ -32,12 +25,12 @@
 import android.support.design.widget.Snackbar;
 import android.support.v4.app.ActivityCompat;
 import android.support.v4.app.FragmentTransaction;
-import android.view.Menu;
-import android.view.MenuItem;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
 import android.view.View;
-import android.widget.ViewAnimator;
 
-import common.activities.SampleActivityBase;
+import com.example.android.system.runtimepermissions.camera.CameraPreviewFragment;
+import com.example.android.system.runtimepermissions.contacts.ContactsFragment;
 
 /**
  * Launcher Activity that demonstrates the use of runtime permissions for Android M.
@@ -80,7 +73,7 @@
  * <p>
  * (This class is based on the MainActivity used in the SimpleFragment sample template.)
  */
-public class MainActivity extends SampleActivityBase
+public class MainActivity extends AppCompatActivity
         implements ActivityCompat.OnRequestPermissionsResultCallback {
 
     public static final String TAG = "MainActivity";
@@ -101,9 +94,6 @@
     private static String[] PERMISSIONS_CONTACT = {Manifest.permission.READ_CONTACTS,
             Manifest.permission.WRITE_CONTACTS};
 
-    // Whether the Log Fragment is currently shown.
-    private boolean mLogShown;
-
     /**
      * Root of the layout of this Activity.
      */
@@ -305,60 +295,6 @@
         }
     }
 
-    /* Note: Methods and definitions below are only used to provide the UI for this sample and are
-    not relevant for the execution of the runtime permissions API. */
-
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        getMenuInflater().inflate(R.menu.main, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onPrepareOptionsMenu(Menu menu) {
-        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
-        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
-        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
-
-        return super.onPrepareOptionsMenu(menu);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.menu_toggle_log:
-                mLogShown = !mLogShown;
-                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
-                if (mLogShown) {
-                    output.setDisplayedChild(1);
-                } else {
-                    output.setDisplayedChild(0);
-                }
-                supportInvalidateOptionsMenu();
-                return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    /** Create a chain of targets that will receive log data */
-    @Override
-    public void initializeLogging() {
-        // Wraps Android's native log framework.
-        LogWrapper logWrapper = new LogWrapper();
-        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
-        Log.setLogNode(logWrapper);
-
-        // Filter strips out everything except the message text.
-        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
-        logWrapper.setNext(msgFilter);
-
-        // On screen logging via a fragment with a TextView.
-        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
-                .findFragmentById(R.id.log_fragment);
-        msgFilter.setNext(logFragment.getLogView());
-    }
-
     public void onBackClick(View view) {
         getSupportFragmentManager().popBackStack();
     }
@@ -368,16 +304,11 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         mLayout = findViewById(R.id.sample_main_layout);
-
         if (savedInstanceState == null) {
             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
             RuntimePermissionsFragment fragment = new RuntimePermissionsFragment();
             transaction.replace(R.id.sample_content_fragment, fragment);
             transaction.commit();
         }
-
-        // This method sets up our custom logger, which will print all log messages to the device
-        // screen, as well as to adb logcat.
-        initializeLogging();
     }
 }
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/PermissionUtil.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/PermissionUtil.java
index b9be625..7fbe9a2 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/PermissionUtil.java
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/PermissionUtil.java
@@ -33,7 +33,7 @@
      */
     public static boolean verifyPermissions(int[] grantResults) {
         // At least one result must be checked.
-        if(grantResults.length < 1){
+        if (grantResults.length < 1) {
             return false;
         }
 
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreview.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreview.java
index 1d25b51..7944519 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreview.java
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreview.java
@@ -27,11 +27,13 @@
 
 /**
  * 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
  * http://developer.android.com/guide/topics/media/camera.html
+ * <p>
+ * Using deprecated android.hardware.Camera in order to support {14 < API < 21}.
  */
 public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
 
@@ -41,6 +43,10 @@
     private Camera.CameraInfo mCameraInfo;
     private int mDisplayOrientation;
 
+    public CameraPreview(Context context) {
+        this(context, null, null, 0);
+    }
+
     public CameraPreview(Context context, Camera camera, Camera.CameraInfo cameraInfo,
             int displayOrientation) {
         super(context);
@@ -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/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreviewFragment.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreviewFragment.java
index 871cf75..4268b96 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreviewFragment.java
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreviewFragment.java
@@ -16,18 +16,18 @@
 
 package com.example.android.system.runtimepermissions.camera;
 
-import com.example.android.common.logger.Log;
-import com.example.android.system.runtimepermissions.R;
-
 import android.hardware.Camera;
 import android.os.Bundle;
 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.FrameLayout;
 import android.widget.Toast;
 
+import com.example.android.system.runtimepermissions.R;
+
 /**
  * Displays a {@link CameraPreview} of the first {@link Camera}.
  * An error message is displayed if the Camera is not available.
@@ -55,6 +55,20 @@
         return new CameraPreviewFragment();
     }
 
+    /**
+     * A safe way to get an instance of the Camera object.
+     */
+    public static 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)
+            Log.d(TAG, "Camera " + cameraId + " is not available: " + e.getMessage());
+        }
+        return c; // returns null if camera is unavailable
+    }
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
@@ -96,18 +110,6 @@
         releaseCamera();
     }
 
-    /** A safe way to get an instance of the Camera object. */
-    public static 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)
-            Log.d(TAG, "Camera " + cameraId + " is not available: " + e.getMessage());
-        }
-        return c; // returns null if camera is unavailable
-    }
-
     private void releaseCamera() {
         if (mCamera != null) {
             mCamera.release();        // release the camera for other applications
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/contacts/ContactsFragment.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/contacts/ContactsFragment.java
index 19f54fb..e6440f0 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/contacts/ContactsFragment.java
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/com/example/android/system/runtimepermissions/contacts/ContactsFragment.java
@@ -16,9 +16,6 @@
 
 package com.example.android.system.runtimepermissions.contacts;
 
-import com.example.android.common.logger.Log;
-import com.example.android.system.runtimepermissions.R;
-
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
 import android.content.OperationApplicationException;
@@ -27,6 +24,7 @@
 import android.os.RemoteException;
 import android.provider.ContactsContract;
 import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.LoaderManager;
 import android.support.v4.content.CursorLoader;
@@ -37,6 +35,8 @@
 import android.widget.Button;
 import android.widget.TextView;
 
+import com.example.android.system.runtimepermissions.R;
+
 import java.util.ArrayList;
 
 /**
@@ -54,10 +54,6 @@
 public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
 
     private static final String TAG = "Contacts";
-    private TextView mMessageText = null;
-
-    private static String DUMMY_CONTACT_NAME = "__DUMMY CONTACT from runtime permissions sample";
-
     /**
      * Projection for the content provider query includes the id and primary name of a contact.
      */
@@ -67,7 +63,9 @@
      * Sort order for the query. Sorted by primary name in ascending order.
      */
     private static final String ORDER = ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC";
+    private static String DUMMY_CONTACT_NAME = "__DUMMY CONTACT from runtime permissions sample";
 
+    private TextView mMessageText;
 
     /**
      * Creates a new instance of a ContactsFragment.
@@ -83,10 +81,10 @@
             Bundle savedInstanceState) {
         View rootView = inflater.inflate(R.layout.fragment_contacts, container, false);
 
-        mMessageText = (TextView) rootView.findViewById(R.id.contact_message);
+        mMessageText = rootView.findViewById(R.id.contact_message);
 
         // Register a listener to add a dummy contact when a button is clicked.
-        Button button = (Button) rootView.findViewById(R.id.contact_add);
+        Button button = rootView.findViewById(R.id.contact_add);
         button.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
@@ -95,7 +93,7 @@
         });
 
         // Register a listener to display the first contact when a button is clicked.
-        button = (Button) rootView.findViewById(R.id.contact_load);
+        button = rootView.findViewById(R.id.contact_load);
         button.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
@@ -127,7 +125,6 @@
      */
     @Override
     public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
-
         if (cursor != null) {
             final int totalCount = cursor.getCount();
             if (totalCount > 0) {
@@ -136,11 +133,7 @@
                         .getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                 mMessageText.setText(
                         getResources().getString(R.string.contacts_string, totalCount, name));
-                Log.d(TAG, "First contact loaded: " + name);
-                Log.d(TAG, "Total number of contacts: " + totalCount);
-                Log.d(TAG, "Total number of contacts: " + totalCount);
             } else {
-                Log.d(TAG, "List of contacts is empty.");
                 mMessageText.setText(R.string.contacts_empty);
             }
         }
@@ -180,10 +173,9 @@
         ContentResolver resolver = getActivity().getContentResolver();
         try {
             resolver.applyBatch(ContactsContract.AUTHORITY, operations);
-        } catch (RemoteException e) {
-            Log.d(TAG, "Could not add a new contact: " + e.getMessage());
-        } catch (OperationApplicationException e) {
-            Log.d(TAG, "Could not add a new contact: " + e.getMessage());
+        } catch (RemoteException | OperationApplicationException e) {
+            Snackbar.make(mMessageText.getRootView(), "Could not add a new contact: " +
+                    e.getMessage(), Snackbar.LENGTH_LONG);
         }
     }
 }
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/common/activities/SampleActivityBase.java b/prebuilts/gradle/RuntimePermissions/Application/src/main/java/common/activities/SampleActivityBase.java
deleted file mode 100644
index ac3928e..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/java/common/activities/SampleActivityBase.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* 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.
-*/
-
-package common.activities;
-
-import com.example.android.common.logger.Log;
-import com.example.android.common.logger.LogWrapper;
-
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-
-
-/**
- * Base launcher activity, to handle most of the common plumbing for samples.
- */
-public class SampleActivityBase extends AppCompatActivity {
-
-    public static final String TAG = "SampleActivityBase";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    protected  void onStart() {
-        super.onStart();
-        initializeLogging();
-    }
-
-    /** Set up targets to receive log data */
-    public void initializeLogging() {
-        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
-        // Wraps Android's native log framework
-        LogWrapper logWrapper = new LogWrapper();
-        Log.setLogNode(logWrapper);
-
-        Log.i(TAG, "Ready");
-    }
-}
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout-w720dp/activity_main.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout-w720dp/activity_main.xml
deleted file mode 100644
index c9a52f6..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout-w720dp/activity_main.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<!--
-  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/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/activity_main.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/activity_main.xml
index 64e8322..c684400 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/activity_main.xml
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/activity_main.xml
@@ -14,52 +14,46 @@
   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">
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/sample_main_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
     <ViewAnimator
-          android:id="@+id/sample_output"
-          android:layout_width="match_parent"
-          android:layout_height="0px"
-          android:layout_weight="1">
+        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">
+            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" />
+                style="@style/Widget.SampleMessage"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingBottom="@dimen/vertical_page_margin"
+                android:paddingLeft="@dimen/horizontal_page_margin"
+                android:paddingRight="@dimen/horizontal_page_margin"
+                android:paddingTop="@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" />
+        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" />
+        android:id="@+id/sample_content_fragment"
+        android:layout_width="match_parent"
+        android:layout_height="0px"
+        android:layout_weight="2" />
 
 </LinearLayout>
 
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_camera.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_camera.xml
index ecdc54a..b2cc9a5 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_camera.xml
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_camera.xml
@@ -14,20 +14,20 @@
  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:layout_height="match_parent"
+              android:orientation="vertical">
+
     <Button
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/back"
-            android:onClick="onBackClick"
-            android:layout_gravity="center_horizontal"/>
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:onClick="onBackClick"
+        android:text="@string/back" />
 
     <FrameLayout
-            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="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
 </LinearLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_camera_unavailable.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_camera_unavailable.xml
index 200ebbc..a56a0e1 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_camera_unavailable.xml
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_camera_unavailable.xml
@@ -14,29 +14,29 @@
  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:layout_height="match_parent"
+              android:orientation="vertical">
 
     <Button
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/back"
-            android:onClick="onBackClick"
-            android:layout_gravity="center_horizontal"/>
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:onClick="onBackClick"
+        android:text="@string/back" />
 
     <ScrollView
-            android:layout_width="match_parent"
-            android:layout_height="fill_parent">
+        android:layout_width="match_parent"
+        android:layout_height="fill_parent">
 
         <TextView
-                android:layout_width="wrap_content"
-                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/camera_unavailable"/>
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingBottom="@dimen/vertical_page_margin"
+            android:paddingLeft="@dimen/horizontal_page_margin"
+            android:paddingRight="@dimen/horizontal_page_margin"
+            android:paddingTop="@dimen/vertical_page_margin"
+            android:text="@string/camera_unavailable" />
 
     </ScrollView>
 
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_contacts.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_contacts.xml
index 8a70fe2..409a284 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_contacts.xml
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_contacts.xml
@@ -14,41 +14,42 @@
  limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
+              android:id="@+id/contacts_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"
-              android:paddingBottom="@dimen/vertical_page_margin">
+              android:paddingTop="@dimen/vertical_page_margin">
 
     <Button
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/back"
-            android:onClick="onBackClick"
-            android:layout_gravity="center_horizontal"/>
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:onClick="onBackClick"
+        android:text="@string/back" />
 
     <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/contacts_intro"/>
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/contacts_intro" />
 
     <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/contact_message"/>
+        android:id="@+id/contact_message"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 
     <Button
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/add_contact"
-            android:id="@+id/contact_add"/>
+        android:id="@+id/contact_add"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/add_contact" />
 
     <Button
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/show_contact"
-            android:id="@+id/contact_load"/>
+        android:id="@+id/contact_load"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/show_contact" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_main.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_main.xml
index f9bfd5f..9adc869 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_main.xml
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/layout/fragment_main.xml
@@ -18,31 +18,31 @@
               xmlns:tools="http://schemas.android.com/tools"
               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"
-              android:paddingBottom="@dimen/vertical_page_margin"
-              android:orientation="vertical"
-              tools:context=".MainActivityFragment">
+              tools:context=".RuntimePermissionsFragment">
 
     <TextView
-            android:text="@string/main_introduction"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"/>
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/main_introduction" />
 
     <Button
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/show_camera"
-            android:id="@+id/button_camera"
-            android:onClick="showCamera"/>
+        android:id="@+id/button_camera"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="showCamera"
+        android:text="@string/show_camera" />
 
 
     <Button
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/show_contacts"
-            android:id="@+id/button_contacts"
-            android:onClick="showContacts"/>
+        android:id="@+id/button_contacts"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="showContacts"
+        android:text="@string/show_contacts" />
 
 </LinearLayout>
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/menu/main.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/menu/main.xml
deleted file mode 100644
index b49c2c5..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/menu/main.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-  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">
-    <item android:id="@+id/menu_toggle_log"
-          android:showAsAction="always"
-          android:title="@string/sample_show_log" />
-</menu>
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-sw600dp/template-dimens.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-sw600dp/template-dimens.xml
deleted file mode 100644
index 22074a2..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-sw600dp/template-dimens.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-  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/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-sw600dp/template-styles.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-sw600dp/template-styles.xml
deleted file mode 100644
index 03d1974..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-sw600dp/template-styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-  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/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-v11/template-styles.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-v11/template-styles.xml
deleted file mode 100644
index 8c1ea66..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-v11/template-styles.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-  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/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-v21/base-colors.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-v21/base-colors.xml
deleted file mode 100644
index 8b6ec3f..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-v21/base-colors.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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>
-
-
-</resources>
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-v21/base-template-styles.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-v21/base-template-styles.xml
deleted file mode 100644
index c778e4f..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values-v21/base-template-styles.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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">
-    </style>
-
-</resources>
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/base-strings.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/base-strings.xml
deleted file mode 100644
index 33c535a..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/base-strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?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">RuntimePermissions</string>
-    <string name="intro_message">
-        <![CDATA[
-        
-            
-            This sample shows runtime permissions available in Android M and above.
-            Display the log on screen to follow the execution.
-            If executed on an Android M device, an additional option to access contacts is shown
-            that is declared with optional, M and above only permissions.
-            
-        
-        ]]>
-    </string>
-</resources>
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/template-dimens.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/dimens.xml
similarity index 92%
rename from prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/template-dimens.xml
rename to prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/dimens.xml
index 39e710b..7655ec9 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/template-dimens.xml
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/dimens.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright 2013 The Android Open Source Project
+  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.
@@ -13,9 +14,7 @@
   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>
@@ -28,5 +27,4 @@
 
     <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
     <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
-</resources>
+</resources>
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/fragmentview_strings.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/fragmentview_strings.xml
deleted file mode 100644
index 7b9d9ec..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/fragmentview_strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
-  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/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/strings.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/strings.xml
index edd2c15..081efe3 100644
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/strings.xml
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/strings.xml
@@ -1,5 +1,33 @@
 <?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>
+    <string name="app_name">RuntimePermissions</string>
+    <string name="intro_message">
+        <![CDATA[
+
+
+            This sample shows runtime permissions available in Android M and above.
+            Display the log on screen to follow the execution.
+            If executed on an Android M device, an additional option to access contacts is shown
+            that is declared with optional, M and above only permissions.
+
+
+        ]]>
+    </string>
     <string name="ok">OK</string>
     <string name="contacts_string">Total number of contacts: %1$,d\nFirst contact:<b>%2$s</b></string>
     <string name="contacts_none">No contacts stored on device.</string>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/template-styles.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/styles.xml
similarity index 93%
copy from prebuilts/gradle/AutofillFramework/Application/src/main/res/values/template-styles.xml
copy to prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/styles.xml
index 6e7d593..f7847b5 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/template-styles.xml
+++ b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/styles.xml
@@ -1,5 +1,5 @@
 <!--
-  Copyright 2013 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.
@@ -13,11 +13,7 @@
   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" />
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/template-styles.xml b/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/template-styles.xml
deleted file mode 100644
index 6e7d593..0000000
--- a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/values/template-styles.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-  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/prebuilts/gradle/RuntimePermissions/NOTICE b/prebuilts/gradle/RuntimePermissions/NOTICE
new file mode 100644
index 0000000..8f8105a
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/NOTICE
@@ -0,0 +1,16 @@
+
+This sample uses the following software:
+
+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.
diff --git a/prebuilts/gradle/RuntimePermissions/README.md b/prebuilts/gradle/RuntimePermissions/README.md
index 0685d1e..867758c 100644
--- a/prebuilts/gradle/RuntimePermissions/README.md
+++ b/prebuilts/gradle/RuntimePermissions/README.md
@@ -31,8 +31,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/RuntimePermissions/build.gradle b/prebuilts/gradle/RuntimePermissions/build.gradle
index 1dac6de..9a2f495 100644
--- a/prebuilts/gradle/RuntimePermissions/build.gradle
+++ b/prebuilts/gradle/RuntimePermissions/build.gradle
@@ -1,3 +1,21 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+  repositories {
+    jcenter()
+  }
+  dependencies {
+    classpath 'com.android.tools.build:gradle:2.3.3'
+  }
+}
+
+allprojects {
+  repositories {
+    jcenter()
+    maven {
+      url 'https://maven.google.com'
+    }
+  }
+}
 
 
 
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/build.gradle b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/build.gradle
new file mode 100644
index 0000000..d9fa949
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/build.gradle
@@ -0,0 +1,37 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion 26
+    buildToolsVersion "26.0.1"
+    defaultConfig {
+        applicationId "com.example.android.system.runtimepermissions"
+        minSdkVersion 15
+        targetSdkVersion 26
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+        exclude group: 'com.android.support', module: 'support-annotations'
+    })
+    compile "com.android.support:support-v13:26.0.0"
+    compile "com.android.support:appcompat-v7:26.0.0"
+    compile 'com.android.support:design:26.0.0'
+    testCompile 'junit:junit:4.12'
+    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+}
+repositories {
+    mavenCentral()
+}
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/proguard-rules.pro b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/proguard-rules.pro
new file mode 100644
index 0000000..2136b0c
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in <sdk root>/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# 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 *;
+#}
+
+# 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/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/AndroidManifest.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e84bbd5
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.example.android.system.runtimepermissions">
+
+    <!-- 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" />
+
+    <!-- The following permissions are only requested if the device is on M or above.
+     On older platforms these permissions are not requested and will not be available. -->
+    <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" />
+    <uses-permission-sdk-23 android:name="android.permission.WRITE_CONTACTS" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.AppCompat.Light">
+        <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/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/MainActivity.kt b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/MainActivity.kt
new file mode 100644
index 0000000..f1dfeee
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/MainActivity.kt
@@ -0,0 +1,269 @@
+/*
+* 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.system.runtimepermissions
+
+import android.Manifest
+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.util.Log
+import android.view.View
+import com.example.android.system.runtimepermissions.camera.CameraPreviewFragment
+import com.example.android.system.runtimepermissions.contacts.ContactsFragment
+import com.example.android.system.runtimepermissions.extensions.batchRequestPermissions
+import com.example.android.system.runtimepermissions.extensions.containsOnly
+import com.example.android.system.runtimepermissions.extensions.isPermissionGranted
+import com.example.android.system.runtimepermissions.extensions.requestPermission
+import com.example.android.system.runtimepermissions.extensions.shouldShowPermissionRationale
+import kotlinx.android.synthetic.main.activity_main.*
+
+/**
+ * Launcher Activity that demonstrates the use of runtime permissions for Android M.
+ * It contains a summary sample description, sample log and a Fragment that calls callbacks on this
+ * Activity to illustrate parts of the runtime permissions API.
+ *
+ *
+ * This Activity requests permissions to access the camera ([android.Manifest.permission.CAMERA])
+ * when the 'Show Camera' button is clicked to display the camera preview.
+ * Contacts permissions (([android.Manifest.permission.READ_CONTACTS] and ([ ][android.Manifest.permission.WRITE_CONTACTS])) are requested when the 'Show and Add Contacts'
+ * button is
+ * clicked to display the first contact in the contacts database and to add a dummy contact
+ * directly to it. Permissions are verified and requested through compat helpers in the support v4
+ * library, in this Activity using [ActivityCompat].
+ * First, permissions are checked if they have already been granted through [ ][ActivityCompat.checkSelfPermission].
+ * If permissions have not been granted, they are requested through
+ * [ActivityCompat.requestPermissions] and the return value checked
+ * in
+ * a callback to the [android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback]
+ * interface.
+ *
+ *
+ * Before requesting permissions, [ActivityCompat.shouldShowRequestPermissionRationale]
+ * should be called to provide the user with additional context for the use of permissions if they
+ * have been denied previously.
+ *
+ *
+ * If this sample is executed on a device running a platform version below M, all permissions
+ * declared
+ * in the Android manifest file are always granted at install time and cannot be requested at run
+ * time.
+ *
+ *
+ * This sample targets the M platform and must therefore request permissions at runtime. Change the
+ * targetSdk in the file 'Application/build.gradle' to 22 to run the application in compatibility
+ * mode.
+ * Now, if a permission has been disable by the system through the application settings, disabled
+ * APIs provide compatibility data.
+ * For example the camera cannot be opened or an empty list of contacts is returned. No special
+ * action is required in this case.
+ *
+ *
+ * (This class is based on the MainActivity used in the SimpleFragment sample template.)
+ */
+class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+        if (savedInstanceState == null) {
+            supportFragmentManager.beginTransaction().apply {
+                replace(R.id.sampleContentFragment, RuntimePermissionsFragment())
+            }.commit()
+        }
+    }
+
+    /**
+     * Called when the 'show camera' button is clicked.
+     * Callback is defined in resource layout definition.
+     */
+    fun showCamera(view: View) {
+        Log.i(TAG, "Show camera button pressed. Checking permission.")
+        // Check if the Camera permission is already available.
+        if (!isPermissionGranted(Manifest.permission.CAMERA)) {
+            // Camera permission has not been granted.
+            requestCameraPermission()
+        } else {
+            // Camera permissions is already available, show the camera preview.
+            Log.i(TAG,
+                    "CAMERA permission has already been granted. Displaying camera preview.")
+            showCameraPreview()
+        }
+    }
+
+    /**
+     * Requests the Camera permission.
+     * If the permission has been denied previously, a SnackBar will prompt the user to grant the
+     * permission, otherwise it is requested directly.
+     */
+    private fun requestCameraPermission() {
+        Log.i(TAG, "CAMERA permission has NOT been granted. Requesting permission.")
+        if (shouldShowPermissionRationale(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.
+            // For example if the user has previously denied the permission.
+            Log.i(TAG, "Displaying camera permission rationale to provide additional context.")
+            Snackbar.make(mainLayout, R.string.permission_camera_rationale,
+                    Snackbar.LENGTH_INDEFINITE)
+                    .setAction(R.string.ok, {
+                        requestPermission(Manifest.permission.CAMERA, REQUEST_CAMERA)
+                    })
+                    .show()
+        } else {
+
+            // Camera permission has not been granted yet. Request it directly.
+            requestPermission(Manifest.permission.CAMERA, REQUEST_CAMERA)
+        }
+    }
+
+    /**
+     * Called when the 'show camera' button is clicked.
+     * Callback is defined in resource layout definition.
+     */
+    fun showContacts(view: View) {
+        Log.i(TAG, "Show contacts button pressed. Checking permissions.")
+
+        // Verify that all required contact permissions have been granted.
+        if (!isPermissionGranted(Manifest.permission.READ_CONTACTS) ||
+                !isPermissionGranted(Manifest.permission.WRITE_CONTACTS)) {
+            // Contacts permissions have not been granted.
+            Log.i(TAG, "Contact permissions has NOT been granted. Requesting permissions.")
+            requestContactsPermissions()
+        } else {
+            // Contact permissions have been granted. Show the contacts fragment.
+            Log.i(TAG,
+                    "Contact permissions have already been granted. Displaying contact details.")
+            showContactDetails()
+        }
+    }
+
+    /**
+     * Requests the Contacts permissions.
+     * If the permission has been denied previously, a Snackbar will prompt the user to grant the
+     * permission, otherwise it is requested directly.
+     */
+    private fun requestContactsPermissions() {
+        if (shouldShowPermissionRationale(Manifest.permission.READ_CONTACTS) ||
+                shouldShowPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
+
+            // 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.
+            // For example, if the request has been denied previously.
+            Log.i(TAG, "Displaying contacts permission rationale to provide additional context.")
+
+            // Display a SnackBar with an explanation and a button to trigger the request.
+            Snackbar.make(mainLayout, R.string.permission_contacts_rationale,
+                    Snackbar.LENGTH_INDEFINITE)
+                    .setAction(R.string.ok, {
+                        batchRequestPermissions(PERMISSIONS_CONTACT, REQUEST_CONTACTS)
+                    })
+                    .show()
+        } else {
+            // Contact permissions have not been granted yet. Request them directly.
+            batchRequestPermissions(PERMISSIONS_CONTACT, REQUEST_CONTACTS)
+        }
+    }
+
+    /**
+     * Display the [CameraPreviewFragment] in the content area if the required Camera
+     * permission has been granted.
+     */
+    private fun showCameraPreview() {
+        supportFragmentManager.beginTransaction()
+                .replace(R.id.sampleContentFragment, CameraPreviewFragment.newInstance())
+                .addToBackStack("contacts")
+                .commit()
+    }
+
+    /**
+     * Display the [ContactsFragment] in the content area if the required contacts
+     * permissions have been granted.
+     */
+    private fun showContactDetails() {
+        supportFragmentManager.beginTransaction()
+                .replace(R.id.sampleContentFragment, ContactsFragment.newInstance())
+                .addToBackStack("contacts")
+                .commit()
+    }
+
+    /**
+     * Callback received when a permissions request has been completed.
+     */
+    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
+            grantResults: IntArray) {
+
+        if (requestCode == REQUEST_CAMERA) {
+            // Received permission result for camera permission.
+            Log.i(TAG, "Received response for Camera permission request.")
+
+            // Check if the permission has been granted
+            if (grantResults.containsOnly(PackageManager.PERMISSION_GRANTED)) {
+                // Camera permission has been granted, preview can be displayed
+                Log.i(TAG, "CAMERA permission has now been granted. Showing preview.")
+                Snackbar.make(mainLayout, R.string.permision_available_camera,
+                        Snackbar.LENGTH_SHORT).show()
+            } else {
+                Log.i(TAG, "CAMERA permission was NOT granted.")
+                Snackbar.make(mainLayout, R.string.permissions_not_granted,
+                        Snackbar.LENGTH_SHORT).show()
+
+            }
+        } else if (requestCode == REQUEST_CONTACTS) {
+            Log.i(TAG, "Received response for contact permissions request.")
+
+            // We have requested multiple permissions for contacts, so all of them need to be
+            // checked.
+            if (grantResults.containsOnly(PackageManager.PERMISSION_GRANTED)) {
+                // All required permissions have been granted, display contacts fragment.
+                Snackbar.make(mainLayout, R.string.permision_available_contacts,
+                        Snackbar.LENGTH_SHORT)
+                        .show()
+            } else {
+                Log.i(TAG, "Contacts permissions were NOT granted.")
+                Snackbar.make(mainLayout, R.string.permissions_not_granted,
+                        Snackbar.LENGTH_SHORT)
+                        .show()
+            }
+
+        } else {
+            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+        }
+    }
+
+    fun onBackClick(view: View) {
+        supportFragmentManager.popBackStack()
+    }
+
+    companion object {
+
+        const val TAG = "MainActivity"
+        /**
+         * Id to identify a camera permission request.
+         */
+        const val REQUEST_CAMERA = 0
+        /**
+         * Id to identify a contacts permission request.
+         */
+        const val REQUEST_CONTACTS = 1
+        /**
+         * Permissions required to read and write contacts. Used by the [ContactsFragment].
+         */
+        val PERMISSIONS_CONTACT = arrayOf(Manifest.permission.READ_CONTACTS,
+                Manifest.permission.WRITE_CONTACTS)
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/RuntimePermissionsFragment.kt b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/RuntimePermissionsFragment.kt
new file mode 100644
index 0000000..91a73c0
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/RuntimePermissionsFragment.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.system.runtimepermissions
+
+import android.os.Build
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import kotlinx.android.synthetic.main.fragment_main.*
+
+class RuntimePermissionsFragment : Fragment() {
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+            savedInstanceState: Bundle?): View =
+            inflater.inflate(R.layout.fragment_main, container, false).apply {
+                if (Build.VERSION.SDK_INT < 23) {
+                    /*
+                    The contacts permissions have been declared in the AndroidManifest for Android M
+                    and above only. They are not available on older platforms, so we are hiding the
+                    button to access the contacts database.
+                    This shows how new runtime-only permissions can be added, that do not apply to
+                    older platform versions. This can be useful for automated updates where
+                    additional permissions might prompt the user on upgrade.
+                     */
+                    contactsButton.visibility = View.GONE
+                }
+            }
+}
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreview.kt b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreview.kt
new file mode 100644
index 0000000..187b55e
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreview.kt
@@ -0,0 +1,117 @@
+/*
+* 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.system.runtimepermissions.camera
+
+import android.content.Context
+import android.hardware.Camera
+import android.util.Log
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import com.example.android.system.runtimepermissions.extensions.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
+ *
+ *
+ * Using deprecated android.hardware.Camera API in order to support {14 < API < 21}.
+ */
+class CameraPreview @JvmOverloads constructor(
+        context: Context,
+        private val camera: Camera? = null,
+        private val cameraInfo: Camera.CameraInfo? = null,
+        private val displayOrientation: Int = 0
+) : SurfaceView(context), SurfaceHolder.Callback {
+
+    private var surfaceHolder: SurfaceHolder? = null
+
+    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.
+            surfaceHolder = holder.apply {
+                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 (surfaceHolder?.surface == null) {
+            // preview surface does not exist
+            Log.d(TAG, "Preview surface does not exist")
+            return
+        }
+
+        // stop preview before making changes
+        try {
+            camera?.run {
+                stopPreview()
+                Log.d(TAG, "Preview stopped.")
+            }
+        } catch (e: Exception) {
+            // ignore: tried to stop a non-existent preview
+            Log.d(TAG, "Error starting camera preview: " + e.message)
+        }
+
+        try {
+            camera?.run {
+                cameraInfo?.run {
+                    setDisplayOrientation(calculatePreviewOrientation(displayOrientation))
+                }
+                setPreviewDisplay(surfaceHolder)
+                startPreview()
+                Log.d(TAG, "Camera preview started.")
+            }
+        } catch (e: Exception) {
+            Log.d(TAG, "Error starting camera preview: " + e.message)
+        }
+    }
+
+    companion object {
+        private const val TAG = "CameraPreview"
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreviewFragment.kt b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreviewFragment.kt
new file mode 100644
index 0000000..2edbfba
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/camera/CameraPreviewFragment.kt
@@ -0,0 +1,99 @@
+/*
+* 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.system.runtimepermissions.camera
+
+import android.hardware.Camera
+import android.os.Bundle
+import android.support.design.widget.Snackbar
+import android.support.v4.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.example.android.system.runtimepermissions.R
+import kotlinx.android.synthetic.main.fragment_camera.*
+
+/**
+ * Displays a [CameraPreview] of the first [Camera].
+ * An error message is displayed if the Camera is not available.
+ *
+ *
+ * This Fragment 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 CameraPreviewFragment : Fragment() {
+
+    private lateinit var preview: CameraPreview
+    private var camera: Camera? = null
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+            savedInstanceState: Bundle?): View {
+
+        // Open an instance of the first camera and retrieve its info.
+        camera = Camera.open(CAMERA_ID)
+        val cameraInfo: Camera.CameraInfo = Camera.CameraInfo()
+
+        if (camera != null) {
+            // Get camera info only if the camera is available
+            Camera.getCameraInfo(CAMERA_ID, cameraInfo)
+        }
+
+        val root: View
+
+        if (camera == null) {
+            // Camera is not available, display error message
+            root = inflater.inflate(R.layout.fragment_camera_unavailable, container, false)
+            Snackbar.make(root, "Camera is not available.", Snackbar.LENGTH_SHORT).show()
+        } else {
+            root = inflater.inflate(R.layout.fragment_camera, container, false)
+
+            // Get the rotation of the screen to adjust the preview image accordingly.
+            val displayRotation = activity.windowManager.defaultDisplay.rotation
+
+            // Create the Preview view and set it as the content of this Activity.
+            preview = CameraPreview(activity, camera, cameraInfo, displayRotation)
+            cameraPreview.addView(preview)
+        }
+
+        return root
+    }
+
+    override fun onPause() {
+        super.onPause()
+        // Stop camera access
+        releaseCamera()
+    }
+
+    private fun releaseCamera() {
+        camera?.release() // release the camera for other applications.
+        camera = null
+    }
+
+    companion object {
+
+        /**
+         * Id of the camera to access. 0 is the first camera.
+         */
+        private const val CAMERA_ID = 0
+
+        fun newInstance() = CameraPreviewFragment()
+    }
+}
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/contacts/ContactsFragment.kt b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/contacts/ContactsFragment.kt
new file mode 100644
index 0000000..b7af99f
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/contacts/ContactsFragment.kt
@@ -0,0 +1,153 @@
+/*
+* 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.
+*/
+
+package com.example.android.system.runtimepermissions.contacts
+
+import android.content.ContentProviderOperation
+import android.content.OperationApplicationException
+import android.database.Cursor
+import android.os.Bundle
+import android.os.RemoteException
+import android.provider.ContactsContract
+import android.support.design.widget.Snackbar
+import android.support.v4.app.Fragment
+import android.support.v4.app.LoaderManager
+import android.support.v4.content.CursorLoader
+import android.support.v4.content.Loader
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.example.android.system.runtimepermissions.R
+import kotlinx.android.synthetic.main.fragment_contacts.*
+import java.util.ArrayList
+
+/**
+ * Displays the first contact stored on the device and contains an option to add a dummy contact.
+ *
+ *
+ * This Fragment is only used to illustrate that access to the Contacts ContentProvider API has
+ * been granted (or denied) as part of the runtime permissions model. It is not relevant for the
+ * use
+ * of the permissions API.
+ *
+ *
+ * This fragments demonstrates a basic use case for accessing the Contacts Provider. The
+ * implementation is based on the training guide available here:
+ * https://developer.android.com/training/contacts-provider/retrieve-names.html
+ */
+class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> {
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+            savedInstanceState: Bundle?): View =
+            inflater.inflate(R.layout.fragment_contacts, container, false).apply {
+                // Register a listener to add a dummy contact when a button is clicked.
+                contactAddButton.setOnClickListener { insertDummyContact() }
+
+                // Register a listener to display the first contact when a button is clicked.
+                contactLoadButton.setOnClickListener { loadContact() }
+            }
+
+    /**
+     * Restart the Loader to query the Contacts content provider to display the first contact.
+     */
+    private fun loadContact() {
+        loaderManager.restartLoader(0, Bundle(), this)
+    }
+
+    /**
+     * Initialises a new [CursorLoader] that queries the [ContactsContract].
+     */
+    override fun onCreateLoader(i: Int, bundle: Bundle): Loader<Cursor> =
+            CursorLoader(activity, ContactsContract.Contacts.CONTENT_URI, PROJECTION, null, null,
+                    ORDER)
+
+
+    /**
+     * Dislays either the name of the first contact or a message.
+     */
+    override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor?) {
+        cursor?.run {
+            if (count > 0) {
+                moveToFirst()
+                val name = getString(getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
+                contactMessage.text = resources.getString(R.string.contacts_string, count, name)
+            } else {
+                contactMessage.text = resources.getString(R.string.contacts_empty)
+            }
+        }
+    }
+
+    override fun onLoaderReset(loader: Loader<Cursor>) {
+        contactMessage.text = getString(R.string.contacts_empty)
+    }
+
+    /**
+     * Accesses the Contacts content provider directly to insert a new contact.
+     *
+     *
+     * The contact is called "__DUMMY ENTRY" and only contains a name.
+     */
+    private fun insertDummyContact() {
+        // Two operations are needed to insert a new contact.
+        val operations = ArrayList<ContentProviderOperation>(2)
+
+        // First, set up a new raw contact.
+        operations.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
+                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
+                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
+                .build())
+
+        // Next, set the name for the contact.
+        operations.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+                .withValue(ContactsContract.Data.MIMETYPE,
+                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
+                        DUMMY_CONTACT_NAME)
+                .build())
+
+        // Apply the operations.
+        try {
+            activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
+        } catch (e: RemoteException) {
+            Snackbar.make(contactMessage.rootView, "Could not add a new contact: " + e.message,
+                    Snackbar.LENGTH_LONG)
+        } catch (e: OperationApplicationException) {
+            Snackbar.make(contactMessage.rootView, "Could not add a new contact: " + e.message,
+                    Snackbar.LENGTH_LONG)
+        }
+
+    }
+
+    companion object {
+
+        /**
+         * Projection for the content provider query includes the id and primary name of a contact.
+         */
+        @JvmField val PROJECTION = arrayOf(ContactsContract.Contacts._ID,
+                ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
+        /**
+         * Sort order for the query. Sorted by primary name in ascending order.
+         */
+        const val ORDER = ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC"
+        const val DUMMY_CONTACT_NAME = "__DUMMY CONTACT from runtime permissions sample"
+
+        /**
+         * Creates a new instance of a ContactsFragment.
+         */
+        fun newInstance() = ContactsFragment()
+    }
+}
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/extensions/AppCompatActivityExts.kt b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/extensions/AppCompatActivityExts.kt
new file mode 100644
index 0000000..ba1ec2a
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/extensions/AppCompatActivityExts.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.example.android.system.runtimepermissions.extensions
+
+import android.content.pm.PackageManager
+import android.support.v4.app.ActivityCompat
+import android.support.v7.app.AppCompatActivity
+
+fun AppCompatActivity.isPermissionGranted(permission: String) =
+        ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
+
+fun AppCompatActivity.shouldShowPermissionRationale(permission: String) =
+        ActivityCompat.shouldShowRequestPermissionRationale(this, permission)
+
+fun AppCompatActivity.requestPermission(permission: String, requestId: Int) =
+        ActivityCompat.requestPermissions(this, arrayOf(permission), requestId)
+
+fun AppCompatActivity.batchRequestPermissions(permissions: Array<String>, requestId: Int) =
+        ActivityCompat.requestPermissions(this, permissions, requestId)
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/extensions/CameraExts.kt b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/extensions/CameraExts.kt
new file mode 100644
index 0000000..ffc6c76
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/extensions/CameraExts.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.system.runtimepermissions.extensions
+
+import android.hardware.Camera
+import android.view.Surface
+
+/**
+ * Calculate the correct orientation for a [Camera] preview that is displayed on screen.
+ *
+ *
+ * Implementation is based on the sample code provided in
+ * [Camera.setDisplayOrientation].
+ */
+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 when (facing) {
+        Camera.CameraInfo.CAMERA_FACING_FRONT -> (360 - ((orientation + degrees) % 360)) % 360
+        Camera.CameraInfo.CAMERA_FACING_BACK -> (orientation - degrees + 360) % 360
+        else -> orientation
+    }
+}
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/extensions/CollectionsExts.kt b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/extensions/CollectionsExts.kt
new file mode 100644
index 0000000..36684e0
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/java/com/example/android/system/runtimepermissions/extensions/CollectionsExts.kt
@@ -0,0 +1,18 @@
+/*
+* 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.system.runtimepermissions.extensions
+
+fun IntArray.containsOnly(num: Int): Boolean = filter { it == num }.isNotEmpty()
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/Application/src/main/res/drawable-hdpi/tile.9.png b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/drawable/tile.9.png
similarity index 100%
rename from prebuilts/gradle/RuntimePermissions/Application/src/main/res/drawable-hdpi/tile.9.png
rename to prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/drawable/tile.9.png
Binary files differ
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/activity_main.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..7e2da81
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,59 @@
+<!--
+  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/mainLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <ViewAnimator
+        android:id="@+id/sampleOutput"
+        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:paddingBottom="@dimen/vertical_page_margin"
+                android:paddingLeft="@dimen/horizontal_page_margin"
+                android:paddingRight="@dimen/horizontal_page_margin"
+                android:paddingTop="@dimen/vertical_page_margin"
+                android:text="@string/intro_message" />
+        </ScrollView>
+
+    </ViewAnimator>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+        android:id="@+id/sampleContentFragment"
+        android:layout_width="match_parent"
+        android:layout_height="0px"
+        android:layout_weight="2" />
+
+</LinearLayout>
+
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_camera.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_camera.xml
new file mode 100644
index 0000000..5245b35
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_camera.xml
@@ -0,0 +1,33 @@
+<!--
+ 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">
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:onClick="onBackClick"
+        android:text="@string/back" />
+
+    <FrameLayout
+        android:id="@+id/cameraPreview"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+</LinearLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_camera_unavailable.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_camera_unavailable.xml
new file mode 100644
index 0000000..bb662d9
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_camera_unavailable.xml
@@ -0,0 +1,43 @@
+<!--
+ 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">
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:onClick="onBackClick"
+        android:text="@string/back" />
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="fill_parent">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingBottom="@dimen/vertical_page_margin"
+            android:paddingLeft="@dimen/horizontal_page_margin"
+            android:paddingRight="@dimen/horizontal_page_margin"
+            android:paddingTop="@dimen/vertical_page_margin"
+            android:text="@string/camera_unavailable" />
+
+    </ScrollView>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_contacts.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_contacts.xml
new file mode 100644
index 0000000..da55692
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_contacts.xml
@@ -0,0 +1,55 @@
+<!--
+ 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/contactsLayout"
+              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">
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:onClick="onBackClick"
+        android:text="@string/back" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/contacts_intro" />
+
+    <TextView
+        android:id="@+id/contactMessage"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button
+        android:id="@+id/contactAddButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/add_contact" />
+
+    <Button
+        android:id="@+id/contactLoadButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/show_contact" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_main.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_main.xml
new file mode 100644
index 0000000..7bfb022
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/layout/fragment_main.xml
@@ -0,0 +1,48 @@
+<!--
+ 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"
+              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=".RuntimePermissionsFragment">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/main_introduction" />
+
+    <Button
+        android:id="@+id/cameraButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="showCamera"
+        android:text="@string/show_camera" />
+
+
+    <Button
+        android:id="@+id/contactsButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="showContacts"
+        android:text="@string/show_contacts" />
+
+</LinearLayout>
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..3279054
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..225fe42
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..c129dbb
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b4ab118
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..99649fb
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-sw600dp/template-dimens.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/colors.xml
similarity index 70%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/res/values-sw600dp/template-dimens.xml
rename to prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/colors.xml
index 22074a2..8d19ba1 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values-sw600dp/template-dimens.xml
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/colors.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright 2013 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.
@@ -13,12 +14,8 @@
   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>
-
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
 </resources>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/template-dimens.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/dimens.xml
similarity index 91%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/res/values/template-dimens.xml
rename to prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/dimens.xml
index 39e710b..2cf1fbe 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/template-dimens.xml
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/dimens.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright 2013 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.
@@ -13,9 +14,7 @@
   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>
@@ -28,5 +27,4 @@
 
     <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
     <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
-</resources>
+</resources>
\ No newline at end of file
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/strings.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..54c043a
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/strings.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.
+  -->
+<resources>
+    <string name="app_name">RuntimePermissions</string>
+    <string name="intro_message">
+        <![CDATA[
+
+
+            This sample shows runtime permissions available in Android M and above.
+            Display the log on screen to follow the execution.
+            If executed on an Android M device, an additional option to access contacts is shown
+            that is declared with optional, M and above only permissions.
+
+
+        ]]>
+    </string>
+    <string name="ok">OK</string>
+    <string name="contacts_string">Total number of contacts: %1$,d\nFirst contact:<b>%2$s</b></string>
+    <string name="contacts_none">No contacts stored on device.</string>
+    <string name="contacts_empty">Contacts not loaded.</string>
+    <string name="add_contact">Add a contact</string>
+    <string name="show_contact">Show first contact</string>
+    <string name="contacts_intro">This fragment demonstrates access to the contact database on the device.\n
+            Clicking \"Add a contact\" adds a new contact named "__DUMMY ENTRY" directly into the database.\n
+    Clicking \"Show first contact\" accesses the contact database to display the name of the first contact.</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="back">Back</string>
+    <string name="show_camera">Show camera preview</string>
+    <string name="show_contacts">Show and add contacts</string>
+    <string name="main_introduction">Click the buttons below to show a camera preview or access the contacts database.\nNote that the contacts option is only available on Android M to illustrate the use of optional, M-only permissions that are not requested on lower SDK platforms.</string>
+    <string name="permision_available_camera">Camera Permission has been granted. Preview can now be opened.</string>
+    <string name="permision_available_contacts">Contacts Permissions have been granted. Contacts screen can now be opened.</string>
+    <string name="permissions_not_granted">Permissions were not granted.</string>
+    <string name="permission_camera_rationale">Camera permission is needed to show the camera preview.</string>
+    <string name="permission_contacts_rationale">Contacts permissions are needed to demonstrate access.</string>
+</resources>
diff --git a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/template-styles.xml b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/styles.xml
similarity index 93%
rename from prebuilts/gradle/AutofillFramework/Application/src/main/res/values/template-styles.xml
rename to prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/styles.xml
index 6e7d593..7adf89d 100644
--- a/prebuilts/gradle/AutofillFramework/Application/src/main/res/values/template-styles.xml
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/app/src/main/res/values/styles.xml
@@ -1,5 +1,5 @@
 <!--
-  Copyright 2013 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.
@@ -13,11 +13,8 @@
   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" />
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/build.gradle b/prebuilts/gradle/RuntimePermissions/kotlinApp/build.gradle
new file mode 100644
index 0000000..e1bc7db
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    ext.kotlin_version = '1.1.4'
+    repositories {
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+allprojects {
+    repositories {
+        jcenter()
+        maven {
+            url 'https://maven.google.com'
+        }
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/gradle.properties b/prebuilts/gradle/RuntimePermissions/kotlinApp/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/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/prebuilts/gradle/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/prebuilts/gradle/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/prebuilts/gradle/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..c0e49f9
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Aug 16 15:09:26 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
diff --git a/prebuilts/gradle/RuntimePermissions/kotlinApp/gradlew b/prebuilts/gradle/RuntimePermissions/kotlinApp/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/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/prebuilts/gradle/RuntimePermissions/kotlinApp/gradlew.bat b/prebuilts/gradle/RuntimePermissions/kotlinApp/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/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/prebuilts/gradle/RuntimePermissions/kotlinApp/settings.gradle b/prebuilts/gradle/RuntimePermissions/kotlinApp/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/prebuilts/gradle/RuntimePermissions/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/prebuilts/gradle/RuntimePermissionsBasic/Application/build.gradle b/prebuilts/gradle/RuntimePermissionsBasic/Application/build.gradle
index 663260f..5e44e39 100644
--- a/prebuilts/gradle/RuntimePermissionsBasic/Application/build.gradle
+++ b/prebuilts/gradle/RuntimePermissionsBasic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.android.support:support-v4:24.0.0'
     compile 'com.android.support:design:24.0.0'
 }
@@ -33,12 +36,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 15
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/RuntimePermissionsBasic/README.md b/prebuilts/gradle/RuntimePermissionsBasic/README.md
index 66bc857..6dd7abd 100644
--- a/prebuilts/gradle/RuntimePermissionsBasic/README.md
+++ b/prebuilts/gradle/RuntimePermissionsBasic/README.md
@@ -22,8 +22,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/RuntimePermissionsWear/Application/build.gradle b/prebuilts/gradle/RuntimePermissionsWear/Application/build.gradle
index b27d2b5..d8a09aa 100644
--- a/prebuilts/gradle/RuntimePermissionsWear/Application/build.gradle
+++ b/prebuilts/gradle/RuntimePermissionsWear/Application/build.gradle
@@ -21,8 +21,8 @@
 dependencies {
     compile 'com.android.support:appcompat-v7:25.3.1'
     compile 'com.android.support:design:25.3.1'
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     compile project(':Shared')
     wearApp project(':Wearable')
 }
@@ -36,13 +36,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
     }
diff --git a/prebuilts/gradle/RuntimePermissionsWear/README.md b/prebuilts/gradle/RuntimePermissionsWear/README.md
index bc15703..68ecd35 100644
--- a/prebuilts/gradle/RuntimePermissionsWear/README.md
+++ b/prebuilts/gradle/RuntimePermissionsWear/README.md
@@ -37,8 +37,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/RuntimePermissionsWear/Shared/build.gradle b/prebuilts/gradle/RuntimePermissionsWear/Shared/build.gradle
index 52e76e2..a7cfb71 100644
--- a/prebuilts/gradle/RuntimePermissionsWear/Shared/build.gradle
+++ b/prebuilts/gradle/RuntimePermissionsWear/Shared/build.gradle
@@ -29,13 +29,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/RuntimePermissionsWear/Wearable/build.gradle b/prebuilts/gradle/RuntimePermissionsWear/Wearable/build.gradle
index bbec133..ad9c5c3 100644
--- a/prebuilts/gradle/RuntimePermissionsWear/Wearable/build.gradle
+++ b/prebuilts/gradle/RuntimePermissionsWear/Wearable/build.gradle
@@ -20,12 +20,12 @@
 
 dependencies {
     compile 'com.android.support:wear:26.0.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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
     compile project(':Shared')
 }
@@ -42,7 +42,7 @@
 
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/ScopedDirectoryAccess/Application/build.gradle b/prebuilts/gradle/ScopedDirectoryAccess/Application/build.gradle
index 6e930b9..7152ba1 100644
--- a/prebuilts/gradle/ScopedDirectoryAccess/Application/build.gradle
+++ b/prebuilts/gradle/ScopedDirectoryAccess/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.android.support:recyclerview-v7:24.0.0'
     compile 'com.android.support:support-v4:24.0.0'
 }
@@ -33,8 +36,10 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 24
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 24
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 24
diff --git a/prebuilts/gradle/ScopedDirectoryAccess/README.md b/prebuilts/gradle/ScopedDirectoryAccess/README.md
index 8f5945f..e9d2742 100644
--- a/prebuilts/gradle/ScopedDirectoryAccess/README.md
+++ b/prebuilts/gradle/ScopedDirectoryAccess/README.md
@@ -37,7 +37,7 @@
 --------------
 
 - Android SDK 24
-- Android Build Tools v25.0.3
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ScreenCapture/Application/build.gradle b/prebuilts/gradle/ScreenCapture/Application/build.gradle
index a96785c..e5ed7ff 100644
--- a/prebuilts/gradle/ScreenCapture/Application/build.gradle
+++ b/prebuilts/gradle/ScreenCapture/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ScreenCapture/README.md b/prebuilts/gradle/ScreenCapture/README.md
index 97f9d33..43a279c 100644
--- a/prebuilts/gradle/ScreenCapture/README.md
+++ b/prebuilts/gradle/ScreenCapture/README.md
@@ -26,8 +26,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/ShareActionProvider/Application/build.gradle b/prebuilts/gradle/ShareActionProvider/Application/build.gradle
index dd4b76e..5307cb6 100644
--- a/prebuilts/gradle/ShareActionProvider/Application/build.gradle
+++ b/prebuilts/gradle/ShareActionProvider/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 9
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/ShareActionProvider/README.md b/prebuilts/gradle/ShareActionProvider/README.md
index 7f39f7e..8a47a1d 100644
--- a/prebuilts/gradle/ShareActionProvider/README.md
+++ b/prebuilts/gradle/ShareActionProvider/README.md
@@ -17,8 +17,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/SkeletonWearableApp/README.md b/prebuilts/gradle/SkeletonWearableApp/README.md
index 91e2a2e..98dc8df 100644
--- a/prebuilts/gradle/SkeletonWearableApp/README.md
+++ b/prebuilts/gradle/SkeletonWearableApp/README.md
@@ -21,8 +21,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/SkeletonWearableApp/Wearable/build.gradle b/prebuilts/gradle/SkeletonWearableApp/Wearable/build.gradle
index 1b4353f..8394315 100644
--- a/prebuilts/gradle/SkeletonWearableApp/Wearable/build.gradle
+++ b/prebuilts/gradle/SkeletonWearableApp/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/SlidingTabsBasic/Application/build.gradle b/prebuilts/gradle/SlidingTabsBasic/Application/build.gradle
index e81066a..9267a5e 100644
--- a/prebuilts/gradle/SlidingTabsBasic/Application/build.gradle
+++ b/prebuilts/gradle/SlidingTabsBasic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 14
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/SlidingTabsBasic/README.md b/prebuilts/gradle/SlidingTabsBasic/README.md
index e66f461..197181e 100644
--- a/prebuilts/gradle/SlidingTabsBasic/README.md
+++ b/prebuilts/gradle/SlidingTabsBasic/README.md
@@ -8,8 +8,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/SlidingTabsColors/Application/build.gradle b/prebuilts/gradle/SlidingTabsColors/Application/build.gradle
index e81066a..9267a5e 100644
--- a/prebuilts/gradle/SlidingTabsColors/Application/build.gradle
+++ b/prebuilts/gradle/SlidingTabsColors/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 14
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/SlidingTabsColors/README.md b/prebuilts/gradle/SlidingTabsColors/README.md
index 29bf531..9dc285f 100644
--- a/prebuilts/gradle/SlidingTabsColors/README.md
+++ b/prebuilts/gradle/SlidingTabsColors/README.md
@@ -25,8 +25,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/SpeedTracker/Application/build.gradle b/prebuilts/gradle/SpeedTracker/Application/build.gradle
index 161b0f3..d40545a 100644
--- a/prebuilts/gradle/SpeedTracker/Application/build.gradle
+++ b/prebuilts/gradle/SpeedTracker/Application/build.gradle
@@ -20,10 +20,10 @@
 
 dependencies {
     compile 'com.android.support:design:25.3.1'
-    compile 'com.google.android.gms:play-services-maps:10.2.4'
-    compile 'com.google.android.gms:play-services-location:10.2.4'
-    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-maps:11.4.0'
+    compile 'com.google.android.gms:play-services-location:11.4.0'
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     compile project(':Shared')
     wearApp project(':Wearable')
 }
@@ -37,13 +37,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
     }
diff --git a/prebuilts/gradle/SpeedTracker/README.md b/prebuilts/gradle/SpeedTracker/README.md
index 1d8522d..d17a972 100644
--- a/prebuilts/gradle/SpeedTracker/README.md
+++ b/prebuilts/gradle/SpeedTracker/README.md
@@ -25,8 +25,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/SpeedTracker/Shared/build.gradle b/prebuilts/gradle/SpeedTracker/Shared/build.gradle
index 52e76e2..a7cfb71 100644
--- a/prebuilts/gradle/SpeedTracker/Shared/build.gradle
+++ b/prebuilts/gradle/SpeedTracker/Shared/build.gradle
@@ -29,13 +29,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/SpeedTracker/Wearable/build.gradle b/prebuilts/gradle/SpeedTracker/Wearable/build.gradle
index 472738b..bc262f9 100644
--- a/prebuilts/gradle/SpeedTracker/Wearable/build.gradle
+++ b/prebuilts/gradle/SpeedTracker/Wearable/build.gradle
@@ -20,13 +20,13 @@
 
 dependencies {
     compile 'com.android.support:wear:26.0.0'
-    compile 'com.google.android.gms:play-services-location:10.2.4'
-    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-location:11.4.0'
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
     compile project(':Shared')
 }
@@ -43,7 +43,7 @@
 
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/StorageClient/Application/build.gradle b/prebuilts/gradle/StorageClient/Application/build.gradle
index ddee143..7473a10 100644
--- a/prebuilts/gradle/StorageClient/Application/build.gradle
+++ b/prebuilts/gradle/StorageClient/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 16
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/StorageClient/README.md b/prebuilts/gradle/StorageClient/README.md
index 0e4dcd4..a7d6e86 100644
--- a/prebuilts/gradle/StorageClient/README.md
+++ b/prebuilts/gradle/StorageClient/README.md
@@ -23,8 +23,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/StorageProvider/Application/build.gradle b/prebuilts/gradle/StorageProvider/Application/build.gradle
index 1132991..274b999 100644
--- a/prebuilts/gradle/StorageProvider/Application/build.gradle
+++ b/prebuilts/gradle/StorageProvider/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,8 +34,10 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 19
diff --git a/prebuilts/gradle/StorageProvider/README.md b/prebuilts/gradle/StorageProvider/README.md
index d5b6760..861de92 100644
--- a/prebuilts/gradle/StorageProvider/README.md
+++ b/prebuilts/gradle/StorageProvider/README.md
@@ -20,8 +20,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/SwipeRefreshLayoutBasic/Application/build.gradle b/prebuilts/gradle/SwipeRefreshLayoutBasic/Application/build.gradle
index e81066a..9267a5e 100644
--- a/prebuilts/gradle/SwipeRefreshLayoutBasic/Application/build.gradle
+++ b/prebuilts/gradle/SwipeRefreshLayoutBasic/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 14
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/SwipeRefreshLayoutBasic/README.md b/prebuilts/gradle/SwipeRefreshLayoutBasic/README.md
index 1cad0bc..9a2df1a 100644
--- a/prebuilts/gradle/SwipeRefreshLayoutBasic/README.md
+++ b/prebuilts/gradle/SwipeRefreshLayoutBasic/README.md
@@ -9,8 +9,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/SwipeRefreshListFragment/Application/build.gradle b/prebuilts/gradle/SwipeRefreshListFragment/Application/build.gradle
index e81066a..9267a5e 100644
--- a/prebuilts/gradle/SwipeRefreshListFragment/Application/build.gradle
+++ b/prebuilts/gradle/SwipeRefreshListFragment/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:support-v13:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 14
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/SwipeRefreshListFragment/README.md b/prebuilts/gradle/SwipeRefreshListFragment/README.md
index 1019223..7e785a8 100644
--- a/prebuilts/gradle/SwipeRefreshListFragment/README.md
+++ b/prebuilts/gradle/SwipeRefreshListFragment/README.md
@@ -23,8 +23,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/SwipeRefreshMultipleViews/Application/build.gradle b/prebuilts/gradle/SwipeRefreshMultipleViews/Application/build.gradle
index dd4b76e..5307cb6 100644
--- a/prebuilts/gradle/SwipeRefreshMultipleViews/Application/build.gradle
+++ b/prebuilts/gradle/SwipeRefreshMultipleViews/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 9
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/SwipeRefreshMultipleViews/README.md b/prebuilts/gradle/SwipeRefreshMultipleViews/README.md
index 4021365..978e247 100644
--- a/prebuilts/gradle/SwipeRefreshMultipleViews/README.md
+++ b/prebuilts/gradle/SwipeRefreshMultipleViews/README.md
@@ -10,8 +10,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/SynchronizedNotifications/Application/build.gradle b/prebuilts/gradle/SynchronizedNotifications/Application/build.gradle
index eec5f81..2e66b87 100644
--- a/prebuilts/gradle/SynchronizedNotifications/Application/build.gradle
+++ b/prebuilts/gradle/SynchronizedNotifications/Application/build.gradle
@@ -19,8 +19,8 @@
 }
 
 dependencies {
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     compile project(':Shared')
     wearApp project(':Wearable')
 }
@@ -34,13 +34,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
     }
diff --git a/prebuilts/gradle/SynchronizedNotifications/README.md b/prebuilts/gradle/SynchronizedNotifications/README.md
index fa5adcc..6a4eec0 100644
--- a/prebuilts/gradle/SynchronizedNotifications/README.md
+++ b/prebuilts/gradle/SynchronizedNotifications/README.md
@@ -51,8 +51,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/SynchronizedNotifications/Shared/build.gradle b/prebuilts/gradle/SynchronizedNotifications/Shared/build.gradle
index 52e76e2..a7cfb71 100644
--- a/prebuilts/gradle/SynchronizedNotifications/Shared/build.gradle
+++ b/prebuilts/gradle/SynchronizedNotifications/Shared/build.gradle
@@ -29,13 +29,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/SynchronizedNotifications/Wearable/build.gradle b/prebuilts/gradle/SynchronizedNotifications/Wearable/build.gradle
index 3b27306..5812016 100644
--- a/prebuilts/gradle/SynchronizedNotifications/Wearable/build.gradle
+++ b/prebuilts/gradle/SynchronizedNotifications/Wearable/build.gradle
@@ -19,12 +19,12 @@
 }
 
 dependencies {
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
     compile project(':Shared')
 }
@@ -39,9 +39,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/TextLinkify/Application/build.gradle b/prebuilts/gradle/TextLinkify/Application/build.gradle
index 12dcfb1..43f4041 100644
--- a/prebuilts/gradle/TextLinkify/Application/build.gradle
+++ b/prebuilts/gradle/TextLinkify/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/TextLinkify/README.md b/prebuilts/gradle/TextLinkify/README.md
index 10fb3bc..d56bfb9 100644
--- a/prebuilts/gradle/TextLinkify/README.md
+++ b/prebuilts/gradle/TextLinkify/README.md
@@ -32,8 +32,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/TextSwitcher/Application/build.gradle b/prebuilts/gradle/TextSwitcher/Application/build.gradle
index 12dcfb1..43f4041 100644
--- a/prebuilts/gradle/TextSwitcher/Application/build.gradle
+++ b/prebuilts/gradle/TextSwitcher/Application/build.gradle
@@ -5,7 +5,7 @@
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0'
+        classpath 'com.android.tools.build:gradle:2.3.3'
     }
 }
 
@@ -13,13 +13,16 @@
 
 repositories {
     jcenter()
+    maven {
+        url 'https://maven.google.com'
+    }
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.0.1"
-    compile "com.android.support:gridlayout-v7:25.0.1"
-    compile "com.android.support:cardview-v7:25.0.1"
-    compile "com.android.support:appcompat-v7:25.0.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
 }
 
 // The sample build uses multiple directories to
@@ -31,12 +34,14 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    
+        compileSdkVersion 26
+
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/TextSwitcher/README.md b/prebuilts/gradle/TextSwitcher/README.md
index 0cc2ce1..626ca72 100644
--- a/prebuilts/gradle/TextSwitcher/README.md
+++ b/prebuilts/gradle/TextSwitcher/README.md
@@ -22,8 +22,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/Timer/README.md b/prebuilts/gradle/Timer/README.md
index 9e53918..1090986 100644
--- a/prebuilts/gradle/Timer/README.md
+++ b/prebuilts/gradle/Timer/README.md
@@ -8,8 +8,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/Timer/Wearable/build.gradle b/prebuilts/gradle/Timer/Wearable/build.gradle
index 1b4353f..8394315 100644
--- a/prebuilts/gradle/Timer/Wearable/build.gradle
+++ b/prebuilts/gradle/Timer/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/WatchFace/Application/build.gradle b/prebuilts/gradle/WatchFace/Application/build.gradle
index 5a9dcbe..59e6691 100644
--- a/prebuilts/gradle/WatchFace/Application/build.gradle
+++ b/prebuilts/gradle/WatchFace/Application/build.gradle
@@ -19,13 +19,13 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.google.android.support:wearable:2.0.3'
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     wearApp project(':Wearable')
 }
 
@@ -39,9 +39,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/WatchFace/README.md b/prebuilts/gradle/WatchFace/README.md
index c83ff14..ab23ecb 100644
--- a/prebuilts/gradle/WatchFace/README.md
+++ b/prebuilts/gradle/WatchFace/README.md
@@ -46,8 +46,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/WatchFace/Wearable/build.gradle b/prebuilts/gradle/WatchFace/Wearable/build.gradle
index ec25dfc..bed2100 100644
--- a/prebuilts/gradle/WatchFace/Wearable/build.gradle
+++ b/prebuilts/gradle/WatchFace/Wearable/build.gradle
@@ -26,12 +26,12 @@
     compile 'com.android.support:wear:26.0.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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -47,7 +47,7 @@
 
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/config/AnalogComplicationConfigRecyclerViewAdapter.java b/prebuilts/gradle/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/config/AnalogComplicationConfigRecyclerViewAdapter.java
index 5af192a..4ee10b5 100644
--- a/prebuilts/gradle/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/config/AnalogComplicationConfigRecyclerViewAdapter.java
+++ b/prebuilts/gradle/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/config/AnalogComplicationConfigRecyclerViewAdapter.java
@@ -518,24 +518,28 @@
                 }
 
             } else if (watchFaceComplicationId == mLeftComplicationId) {
-                if (complicationProviderInfo != null) {
-                    mLeftComplication.setImageIcon(complicationProviderInfo.providerIcon);
-                    mLeftComplicationBackground.setVisibility(View.VISIBLE);
-
-                } else {
-                    mLeftComplication.setImageDrawable(mDefaultComplicationDrawable);
-                    mLeftComplicationBackground.setVisibility(View.INVISIBLE);
-                }
+                updateComplicationView(complicationProviderInfo, mLeftComplication,
+                    mLeftComplicationBackground);
 
             } else if (watchFaceComplicationId == mRightComplicationId) {
-                if (complicationProviderInfo != null) {
-                    mRightComplication.setImageIcon(complicationProviderInfo.providerIcon);
-                    mRightComplicationBackground.setVisibility(View.VISIBLE);
+                updateComplicationView(complicationProviderInfo, mRightComplication,
+                    mRightComplicationBackground);
+            }
+        }
 
-                } else {
-                    mRightComplication.setImageDrawable(mDefaultComplicationDrawable);
-                    mRightComplicationBackground.setVisibility(View.INVISIBLE);
-                }
+        private void updateComplicationView(ComplicationProviderInfo complicationProviderInfo,
+            ImageButton button, ImageView background) {
+            if (complicationProviderInfo != null) {
+                button.setImageIcon(complicationProviderInfo.providerIcon);
+                button.setContentDescription(
+                    mContext.getString(R.string.edit_complication,
+                        complicationProviderInfo.appName + " " +
+                            complicationProviderInfo.providerName));
+                background.setVisibility(View.VISIBLE);
+            } else {
+                button.setImageDrawable(mDefaultComplicationDrawable);
+                button.setContentDescription(mContext.getString(R.string.add_complication));
+                background.setVisibility(View.INVISIBLE);
             }
         }
 
diff --git a/prebuilts/gradle/WatchFace/Wearable/src/main/res/layout/config_list_preview_and_complications_item.xml b/prebuilts/gradle/WatchFace/Wearable/src/main/res/layout/config_list_preview_and_complications_item.xml
index 41fb79a..dba01c9 100644
--- a/prebuilts/gradle/WatchFace/Wearable/src/main/res/layout/config_list_preview_and_complications_item.xml
+++ b/prebuilts/gradle/WatchFace/Wearable/src/main/res/layout/config_list_preview_and_complications_item.xml
@@ -31,7 +31,8 @@
         android:layout_height="@dimen/analog_complication_settings_preview_size"
         android:layout_centerHorizontal="true"
         android:layout_centerVertical="true"
-        android:background="@drawable/settings_watch_face_preview_background"/>
+        android:background="@drawable/settings_watch_face_preview_background"
+        android:importantForAccessibility="no"/>
 
     <View
         android:id="@+id/watch_face_highlight"
@@ -39,7 +40,8 @@
         android:layout_height="@dimen/analog_complication_settings_preview_size"
         android:layout_centerHorizontal="true"
         android:layout_centerVertical="true"
-        android:background="@drawable/settings_watch_face_preview_highlight"/>
+        android:background="@drawable/settings_watch_face_preview_highlight"
+        android:importantForAccessibility="no"/>
 
 
     <View
@@ -48,7 +50,8 @@
         android:layout_height="@dimen/analog_complication_settings_preview_size"
         android:layout_centerHorizontal="true"
         android:layout_centerVertical="true"
-        android:background="@drawable/settings_watch_face_preview_arms_and_ticks"/>
+        android:background="@drawable/settings_watch_face_preview_arms_and_ticks"
+        android:importantForAccessibility="no"/>
 
 
     <ImageView
@@ -59,7 +62,8 @@
         android:layout_centerVertical="true"
         android:src="@drawable/added_complication"
         style="?android:borderlessButtonStyle"
-        android:background="@android:color/transparent"/>
+        android:background="@android:color/transparent"
+        android:importantForAccessibility="no" />
 
     <ImageButton
         android:id="@+id/left_complication"
@@ -78,7 +82,8 @@
         android:layout_centerVertical="true"
         android:src="@drawable/added_complication"
         style="?android:borderlessButtonStyle"
-        android:background="@android:color/transparent"/>
+        android:background="@android:color/transparent"
+        android:importantForAccessibility="no"/>
 
     <ImageButton
         android:id="@+id/right_complication"
@@ -88,4 +93,4 @@
         android:layout_centerVertical="true"
         style="?android:borderlessButtonStyle"
         android:background="@android:color/transparent"/>
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/prebuilts/gradle/WatchFace/Wearable/src/main/res/values/strings.xml b/prebuilts/gradle/WatchFace/Wearable/src/main/res/values/strings.xml
index 0bad170..8dbaccc 100644
--- a/prebuilts/gradle/WatchFace/Wearable/src/main/res/values/strings.xml
+++ b/prebuilts/gradle/WatchFace/Wearable/src/main/res/values/strings.xml
@@ -13,7 +13,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name">WatchFace</string>
 
     <string name="opengl_name">Sample OpenGL</string>
@@ -26,7 +26,6 @@
     <string name="digital_am">AM</string>
     <string name="digital_pm">PM</string>
 
-    <string name="analog_complication_config_name">Configuration</string>
     <string name="complications_provider_incrementing_number">Incrementing Number</string>
 
     <string name="analog_complication_preference_file_key">com.example.android.wearable.watchface.ANALOG_COMPLICATION_PREFERENCE_FILE_KEY</string>
@@ -48,7 +47,10 @@
     <string name="color_navy">Navy</string>
     <string name="color_red">Red</string>
     <string name="color_white">White</string>
-    <string name="analog_complication_config">Analog Complication Config</string>
+
+    <string name="analog_complication_config">Configure Watchface Complications</string>
+    <string name="add_complication">Add Complication</string>
+    <string name="edit_complication">Edit Complication <xliff:g id="name" example="World Clock">%1$s</xliff:g></string>
 
     <string-array name="color_array">
         <item>@string/color_black</item>
diff --git a/prebuilts/gradle/WatchViewStub/README.md b/prebuilts/gradle/WatchViewStub/README.md
index 3ec5a0f..f192681 100644
--- a/prebuilts/gradle/WatchViewStub/README.md
+++ b/prebuilts/gradle/WatchViewStub/README.md
@@ -16,8 +16,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/WatchViewStub/Wearable/build.gradle b/prebuilts/gradle/WatchViewStub/Wearable/build.gradle
index d1db5d1..eafbc95 100644
--- a/prebuilts/gradle/WatchViewStub/Wearable/build.gradle
+++ b/prebuilts/gradle/WatchViewStub/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/WearComplicationProvidersTestSuite/README.md b/prebuilts/gradle/WearComplicationProvidersTestSuite/README.md
index a5278c9..38e6510 100644
--- a/prebuilts/gradle/WearComplicationProvidersTestSuite/README.md
+++ b/prebuilts/gradle/WearComplicationProvidersTestSuite/README.md
@@ -32,8 +32,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/WearComplicationProvidersTestSuite/Wearable/build.gradle b/prebuilts/gradle/WearComplicationProvidersTestSuite/Wearable/build.gradle
index 748a936..e03541c 100644
--- a/prebuilts/gradle/WearComplicationProvidersTestSuite/Wearable/build.gradle
+++ b/prebuilts/gradle/WearComplicationProvidersTestSuite/Wearable/build.gradle
@@ -25,12 +25,12 @@
     compile 'com.android.support:appcompat-v7:26.0.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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -46,7 +46,7 @@
 
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/WearDrawers/README.md b/prebuilts/gradle/WearDrawers/README.md
index c487fcb..bef26ad 100644
--- a/prebuilts/gradle/WearDrawers/README.md
+++ b/prebuilts/gradle/WearDrawers/README.md
@@ -28,8 +28,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/WearDrawers/Wearable/build.gradle b/prebuilts/gradle/WearDrawers/Wearable/build.gradle
index 332123f..7f08251 100644
--- a/prebuilts/gradle/WearDrawers/Wearable/build.gradle
+++ b/prebuilts/gradle/WearDrawers/Wearable/build.gradle
@@ -25,12 +25,12 @@
     compile 'com.android.support:wear:26.0.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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -46,7 +46,7 @@
 
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/WearHighBandwidthNetworking/README.md b/prebuilts/gradle/WearHighBandwidthNetworking/README.md
index 7766611..28d7e98 100644
--- a/prebuilts/gradle/WearHighBandwidthNetworking/README.md
+++ b/prebuilts/gradle/WearHighBandwidthNetworking/README.md
@@ -42,8 +42,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/WearHighBandwidthNetworking/Wearable/build.gradle b/prebuilts/gradle/WearHighBandwidthNetworking/Wearable/build.gradle
index 45663ff..d79b122 100644
--- a/prebuilts/gradle/WearHighBandwidthNetworking/Wearable/build.gradle
+++ b/prebuilts/gradle/WearHighBandwidthNetworking/Wearable/build.gradle
@@ -25,12 +25,12 @@
     compile 'com.android.support:wear:26.0.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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -46,7 +46,7 @@
 
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/WearNotifications/Application/build.gradle b/prebuilts/gradle/WearNotifications/Application/build.gradle
index fb5679c..302c549 100644
--- a/prebuilts/gradle/WearNotifications/Application/build.gradle
+++ b/prebuilts/gradle/WearNotifications/Application/build.gradle
@@ -22,8 +22,8 @@
     compile 'com.android.support:appcompat-v7:26.0.0'
     compile 'com.android.support:cardview-v7:26.0.0'
     compile 'com.android.support:design:26.0.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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     compile project(':Shared')
     wearApp project(':Wearable')
 }
@@ -39,7 +39,7 @@
 android {
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/WearNotifications/Application/src/main/java/com/example/android/wearable/wear/wearnotifications/MainActivity.java b/prebuilts/gradle/WearNotifications/Application/src/main/java/com/example/android/wearable/wear/wearnotifications/MainActivity.java
index 004f2de..ec7e188 100644
--- a/prebuilts/gradle/WearNotifications/Application/src/main/java/com/example/android/wearable/wear/wearnotifications/MainActivity.java
+++ b/prebuilts/gradle/WearNotifications/Application/src/main/java/com/example/android/wearable/wear/wearnotifications/MainActivity.java
@@ -304,6 +304,7 @@
                         getResources(),
                         R.drawable.ic_alarm_white_48dp))
                 .setContentIntent(notifyPendingIntent)
+                .setDefaults(NotificationCompat.DEFAULT_ALL)
                 // Set primary color (important for Wear 2.0 Notifications).
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
@@ -473,6 +474,7 @@
                         getResources(),
                         R.drawable.ic_person_black_48dp))
                 .setContentIntent(mainPendingIntent)
+                .setDefaults(NotificationCompat.DEFAULT_ALL)
                 // Set primary color (important for Wear 2.0 Notifications).
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
@@ -610,6 +612,7 @@
                         getResources(),
                         R.drawable.ic_person_black_48dp))
                 .setContentIntent(mainPendingIntent)
+                .setDefaults(NotificationCompat.DEFAULT_ALL)
                 // Set primary color (important for Wear 2.0 Notifications).
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
@@ -789,6 +792,7 @@
                         getResources(),
                         R.drawable.ic_person_black_48dp))
                 .setContentIntent(mainPendingIntent)
+                .setDefaults(NotificationCompat.DEFAULT_ALL)
                 // Set primary color (important for Wear 2.0 Notifications).
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
diff --git a/prebuilts/gradle/WearNotifications/README.md b/prebuilts/gradle/WearNotifications/README.md
index eaefd5a..624093c 100644
--- a/prebuilts/gradle/WearNotifications/README.md
+++ b/prebuilts/gradle/WearNotifications/README.md
@@ -47,7 +47,7 @@
 --------------
 
 - Android SDK 26
-- Android Build Tools v25.0.3
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/WearNotifications/Shared/build.gradle b/prebuilts/gradle/WearNotifications/Shared/build.gradle
index 0970e28..7e2c7ca 100644
--- a/prebuilts/gradle/WearNotifications/Shared/build.gradle
+++ b/prebuilts/gradle/WearNotifications/Shared/build.gradle
@@ -33,7 +33,7 @@
 android {
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
diff --git a/prebuilts/gradle/WearNotifications/Wearable/build.gradle b/prebuilts/gradle/WearNotifications/Wearable/build.gradle
index 7a0ce21..be5b943 100644
--- a/prebuilts/gradle/WearNotifications/Wearable/build.gradle
+++ b/prebuilts/gradle/WearNotifications/Wearable/build.gradle
@@ -22,12 +22,12 @@
     compile 'com.android.support:appcompat-v7:26.0.0'
     compile 'com.android.support:wear:26.0.0'
     compile 'com.android.support:design:26.0.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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
     compile project(':Shared')
 }
@@ -44,7 +44,7 @@
 
         compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/WearNotifications/Wearable/src/main/java/com/example/android/wearable/wear/wearnotifications/StandaloneMainActivity.java b/prebuilts/gradle/WearNotifications/Wearable/src/main/java/com/example/android/wearable/wear/wearnotifications/StandaloneMainActivity.java
index 28fa1e5..eb8842c 100644
--- a/prebuilts/gradle/WearNotifications/Wearable/src/main/java/com/example/android/wearable/wear/wearnotifications/StandaloneMainActivity.java
+++ b/prebuilts/gradle/WearNotifications/Wearable/src/main/java/com/example/android/wearable/wear/wearnotifications/StandaloneMainActivity.java
@@ -284,6 +284,7 @@
                 .setLargeIcon(BitmapFactory.decodeResource(
                         getResources(),
                         R.drawable.ic_alarm_white_48dp))
+                .setDefaults(NotificationCompat.DEFAULT_ALL)
                 // Set primary color (important for Wear 2.0 Notifications).
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
@@ -453,6 +454,7 @@
                         getResources(),
                         R.drawable.ic_person_black_48dp))
                 .setContentIntent(mainPendingIntent)
+                .setDefaults(NotificationCompat.DEFAULT_ALL)
                 // Set primary color (important for Wear 2.0 Notifications).
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
@@ -554,6 +556,7 @@
                         getResources(),
                         R.drawable.ic_person_black_48dp))
                 .setContentIntent(mainPendingIntent)
+                .setDefaults(NotificationCompat.DEFAULT_ALL)
                 // Set primary color (important for Wear 2.0 Notifications).
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
@@ -710,6 +713,7 @@
                         getResources(),
                         R.drawable.ic_person_black_48dp))
                 .setContentIntent(mainPendingIntent)
+                .setDefaults(NotificationCompat.DEFAULT_ALL)
                 // Set primary color (important for Wear 2.0 Notifications).
                 .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
 
diff --git a/prebuilts/gradle/WearSpeakerSample/README.md b/prebuilts/gradle/WearSpeakerSample/README.md
index 0c50a87..f096dc0 100644
--- a/prebuilts/gradle/WearSpeakerSample/README.md
+++ b/prebuilts/gradle/WearSpeakerSample/README.md
@@ -11,8 +11,8 @@
 Pre-requisites
 --------------
 
-- Android SDK v25
-- Android Build Tools v25.0.3
+- Android SDK v26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Getting Started
diff --git a/prebuilts/gradle/WearVerifyRemoteApp/Application/build.gradle b/prebuilts/gradle/WearVerifyRemoteApp/Application/build.gradle
index e4c34c4..268f88b 100644
--- a/prebuilts/gradle/WearVerifyRemoteApp/Application/build.gradle
+++ b/prebuilts/gradle/WearVerifyRemoteApp/Application/build.gradle
@@ -19,13 +19,13 @@
 }
 
 dependencies {
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
     compile 'com.google.android.support:wearable:2.0.3'
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     wearApp project(':Wearable')
 }
 
@@ -39,9 +39,9 @@
 
 android {
     
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 23
diff --git a/prebuilts/gradle/WearVerifyRemoteApp/README.md b/prebuilts/gradle/WearVerifyRemoteApp/README.md
index fde473b..0ef501d 100644
--- a/prebuilts/gradle/WearVerifyRemoteApp/README.md
+++ b/prebuilts/gradle/WearVerifyRemoteApp/README.md
@@ -30,8 +30,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/WearVerifyRemoteApp/Wearable/build.gradle b/prebuilts/gradle/WearVerifyRemoteApp/Wearable/build.gradle
index fc4aaa4..deb0179 100644
--- a/prebuilts/gradle/WearVerifyRemoteApp/Wearable/build.gradle
+++ b/prebuilts/gradle/WearVerifyRemoteApp/Wearable/build.gradle
@@ -24,12 +24,12 @@
 
 
 
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
 }
 
@@ -43,9 +43,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/prebuilts/gradle/XYZTouristAttractions/Application/build.gradle b/prebuilts/gradle/XYZTouristAttractions/Application/build.gradle
index 234a384..c9e5bf6 100644
--- a/prebuilts/gradle/XYZTouristAttractions/Application/build.gradle
+++ b/prebuilts/gradle/XYZTouristAttractions/Application/build.gradle
@@ -19,14 +19,14 @@
 }
 
 dependencies {
-    compile 'com.google.android.gms:play-services-location:10.2.4'
+    compile 'com.google.android.gms:play-services-location:11.4.0'
     compile 'com.google.maps.android:android-maps-utils:0.3.4'
     compile 'com.github.bumptech.glide:glide:3.6.1'
     compile 'com.android.support:appcompat-v7:25.3.1'
     compile 'com.android.support:recyclerview-v7:25.3.1'
     compile 'com.android.support:design:25.3.1'
-    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.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
     compile project(':Shared')
     wearApp project(':Wearable')
 }
@@ -40,13 +40,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
     }
diff --git a/prebuilts/gradle/XYZTouristAttractions/README.md b/prebuilts/gradle/XYZTouristAttractions/README.md
index 95960fa..6f14603 100644
--- a/prebuilts/gradle/XYZTouristAttractions/README.md
+++ b/prebuilts/gradle/XYZTouristAttractions/README.md
@@ -99,8 +99,8 @@
 Pre-requisites
 --------------
 
-- Android SDK 25
-- Android Build Tools v25.0.3
+- Android SDK 26
+- Android Build Tools v26.0.1
 - Android Support Repository
 
 Screenshots
diff --git a/prebuilts/gradle/XYZTouristAttractions/Shared/build.gradle b/prebuilts/gradle/XYZTouristAttractions/Shared/build.gradle
index 1230b46..13c8ee5 100644
--- a/prebuilts/gradle/XYZTouristAttractions/Shared/build.gradle
+++ b/prebuilts/gradle/XYZTouristAttractions/Shared/build.gradle
@@ -20,8 +20,8 @@
 
 dependencies {
     compile 'com.android.support:support-v13:25.3.1'
-    compile 'com.google.android.gms:play-services-wearable:10.2.4'
-    compile 'com.google.android.gms:play-services-maps:10.2.4'
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.google.android.gms:play-services-maps:11.4.0'
     compile 'com.google.maps.android:android-maps-utils:0.3.4'
 }
 
@@ -34,13 +34,13 @@
     'template'] // boilerplate code that is generated by the sample template process
 
 android {
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         minSdkVersion 18
-        targetSdkVersion 25
+        targetSdkVersion 26
     }
 
     compileOptions {
diff --git a/prebuilts/gradle/XYZTouristAttractions/Wearable/build.gradle b/prebuilts/gradle/XYZTouristAttractions/Wearable/build.gradle
index 79ad46d..25f5450 100644
--- a/prebuilts/gradle/XYZTouristAttractions/Wearable/build.gradle
+++ b/prebuilts/gradle/XYZTouristAttractions/Wearable/build.gradle
@@ -19,13 +19,13 @@
 }
 
 dependencies {
-    compile 'com.google.android.gms:play-services-maps:10.2.4'
-    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-maps:11.4.0'
+    compile 'com.google.android.gms:play-services-wearable:11.4.0'
+    compile 'com.android.support:support-v13:26.1.0'
 
-    provided 'com.google.android.wearable:wearable:2.0.3'
+    provided 'com.google.android.wearable:wearable:2.0.5'
 
-    compile 'com.google.android.support:wearable:2.0.3'
+    compile 'com.google.android.support:wearable:2.0.5'
 
     compile project(':Shared')
 }
@@ -40,9 +40,9 @@
 
 android {
 
-        compileSdkVersion 25
+        compileSdkVersion 26
 
-    buildToolsVersion "25.0.3"
+    buildToolsVersion "26.0.1"
 
     defaultConfig {
         versionCode 1
diff --git a/templates/base-application/_MODULE_/build.gradle.ftl b/templates/base-application/_MODULE_/build.gradle.ftl
index d3b21ae..cb45485 100644
--- a/templates/base-application/_MODULE_/build.gradle.ftl
+++ b/templates/base-application/_MODULE_/build.gradle.ftl
@@ -16,6 +16,9 @@
 buildscript {
     repositories {
         jcenter()
+        maven {
+            url 'https://maven.google.com'
+        }
     }
 
     dependencies {
@@ -41,15 +44,15 @@
 
 <#if !sample.auto_add_support_lib?has_content || sample.auto_add_support_lib == "true">
   <#if sample.minSdk?matches(r'^\d+$') && sample.minSdk?number < 7>
-    compile "com.android.support:support-v4:25.1.1"
+    compile "com.android.support:support-v4:26.1.0"
   <#elseif sample.minSdk?matches(r'^\d+$') && sample.minSdk?number < 13>
-    compile "com.android.support:support-v4:25.1.1"
-    compile "com.android.support:gridlayout-v7:25.1.1"
-    compile "com.android.support:cardview-v7:25.1.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
   <#else>
-    compile "com.android.support:support-v4:25.1.1"
-    compile "com.android.support:support-v13:25.1.1"
-    compile "com.android.support:cardview-v7:25.1.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
   </#if>
 </#if>
 
diff --git a/templates/base/_MODULE_/build.gradle.ftl b/templates/base/_MODULE_/build.gradle.ftl
index 24b9cdb..175dabd 100644
--- a/templates/base/_MODULE_/build.gradle.ftl
+++ b/templates/base/_MODULE_/build.gradle.ftl
@@ -40,18 +40,18 @@
 dependencies {
 <#if !sample.auto_add_support_lib?has_content || sample.auto_add_support_lib == "true">
   <#if sample.minSdk?matches(r'^\d+$') && sample.minSdk?number < 7>
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
   <#elseif sample.minSdk?matches(r'^\d+$') && sample.minSdk?number < 13>
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:gridlayout-v7:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:gridlayout-v7:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
   <#else>
-    compile "com.android.support:support-v4:25.3.1"
-    compile "com.android.support:support-v13:25.3.1"
-    compile "com.android.support:cardview-v7:25.3.1"
-    compile "com.android.support:appcompat-v7:25.3.1"
+    compile "com.android.support:support-v4:26.1.0"
+    compile "com.android.support:support-v13:26.1.0"
+    compile "com.android.support:cardview-v7:26.1.0"
+    compile "com.android.support:appcompat-v7:26.1.0"
   </#if>
 </#if>
 <#list sample.dependency as dep>
diff --git a/templates/include/common.ftl b/templates/include/common.ftl
index a288871..0467ed4 100644
--- a/templates/include/common.ftl
+++ b/templates/include/common.ftl
@@ -39,7 +39,7 @@
 <#elseif (sample.compileSdkVersion)?has_content>
     <#assign compile_sdk = sample.compileSdkVersion/>
 <#else>
-    <#assign compile_sdk = "25"/>
+    <#assign compile_sdk = "26"/>
 </#if>
 <#-- Set the MinSDK version. This is more complicated than it should be, because
       the version can be either a number or a string (e.g. KeyLimePie) so we need to test
@@ -78,13 +78,13 @@
 </#macro>
 
 <#-- Set the global build tools version -->
-<#assign build_tools_version='"25.0.3"'/>
+<#assign build_tools_version='"26.0.1"'/>
 
-<#assign play_services_version="10.2.4"/>
+<#assign play_services_version="11.4.0"/>
 <#assign play_services_wearable_dependency="'com.google.android.gms:play-services-wearable:${play_services_version}'"/>
 
-<#assign android_support_v13_dependency="'com.android.support:support-v13:25.3.1'"/>
+<#assign android_support_v13_dependency="'com.android.support:support-v13:26.1.0'"/>
 
-<#assign wearable_support_dependency="'com.google.android.support:wearable:2.0.3'"/>
+<#assign wearable_support_dependency="'com.google.android.support:wearable:2.0.5'"/>
 
-<#assign wearable_support_provided_dependency="'com.google.android.wearable:wearable:2.0.3'"/>
+<#assign wearable_support_provided_dependency="'com.google.android.wearable:wearable:2.0.5'"/>