Replaces deprecated GridViewPager with WearableRecyclerView.

Bug: 4368433
Test: Manual tests.

Change-Id: Ia85471394685e480ab502ea47eeb28bf6ccf68a9
diff --git a/wearable/wear/DataLayer/Application/src/main/java/com/example/android/wearable/datalayer/MainActivity.java b/wearable/wear/DataLayer/Application/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
index 2f232cc..7673d44 100644
--- a/wearable/wear/DataLayer/Application/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
+++ b/wearable/wear/DataLayer/Application/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
@@ -67,13 +67,13 @@
 
 /**
  * Receives its own events using a listener API designed for foreground activities. Updates a data
- * item every second while it is open. Also allows user to take a photo and send that as an asset
- * to the paired wearable.
+ * item every second while it is open. Also allows user to take a photo and send that as an asset to
+ * the paired wearable.
  */
-public class MainActivity extends Activity implements
-        DataClient.OnDataChangedListener,
-        MessageClient.OnMessageReceivedListener,
-        CapabilityClient.OnCapabilityChangedListener {
+public class MainActivity extends Activity
+        implements DataClient.OnDataChangedListener,
+                MessageClient.OnMessageReceivedListener,
+                CapabilityClient.OnCapabilityChangedListener {
 
     private static final String TAG = "MainActivity";
 
@@ -118,8 +118,9 @@
     @Override
     public void onResume() {
         super.onResume();
-        mDataItemGeneratorFuture = mGeneratorExecutor.scheduleWithFixedDelay(
-                new DataItemGenerator(), 1, 5, TimeUnit.SECONDS);
+        mDataItemGeneratorFuture =
+                mGeneratorExecutor.scheduleWithFixedDelay(
+                        new DataItemGenerator(), 1, 5, TimeUnit.SECONDS);
 
         mStartActivityBtn.setEnabled(true);
         mSendPhotoBtn.setEnabled(mCameraSupported);
@@ -129,8 +130,7 @@
         Wearable.getDataClient(this).addListener(this);
         Wearable.getMessageClient(this).addListener(this);
         Wearable.getCapabilityClient(this)
-                .addListener(
-                        this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE);
+                .addListener(this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE);
     }
 
     @Override
@@ -169,8 +169,12 @@
 
     @Override
     public void onMessageReceived(MessageEvent messageEvent) {
-        LOGD(TAG, "onMessageReceived() A message from watch was received:"
-                + messageEvent.getRequestId() + " " + messageEvent.getPath());
+        LOGD(
+                TAG,
+                "onMessageReceived() A message from watch was received:"
+                        + messageEvent.getRequestId()
+                        + " "
+                        + messageEvent.getPath());
 
         mDataItemListAdapter.add(new Event("Message from watch", messageEvent.toString()));
     }
@@ -182,9 +186,7 @@
         mDataItemListAdapter.add(new Event("onCapabilityChanged", capabilityInfo.toString()));
     }
 
-    /**
-     * Sets up UI components and their callback handlers.
-     */
+    /** Sets up UI components and their callback handlers. */
     private void setupViews() {
         mSendPhotoBtn = findViewById(R.id.sendPhoto);
         mThumbView = findViewById(R.id.imageView);
@@ -202,9 +204,7 @@
         }
     }
 
-    /**
-     * Sends an RPC to start a fullscreen Activity on the wearable.
-     */
+    /** Sends an RPC to start a fullscreen Activity on the wearable. */
     public void onStartWearableActivityClick(View view) {
         LOGD(TAG, "Generating RPC");
 
@@ -234,8 +234,8 @@
     }
 
     /**
-     * Dispatches an {@link android.content.Intent} to take a photo. Result will be returned back
-     * in onActivityResult().
+     * Dispatches an {@link android.content.Intent} to take a photo. Result will be returned back in
+     * onActivityResult().
      */
     private void dispatchTakePictureIntent() {
         Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
@@ -279,12 +279,13 @@
 
         Task<DataItem> dataItemTask = Wearable.getDataClient(this).putDataItem(request);
 
-        dataItemTask.addOnSuccessListener(new OnSuccessListener<DataItem>() {
-            @Override
-            public void onSuccess(DataItem dataItem) {
-                LOGD(TAG, "Sending image was successful: " + dataItem);
-            }
-        });
+        dataItemTask.addOnSuccessListener(
+                new OnSuccessListener<DataItem>() {
+                    @Override
+                    public void onSuccess(DataItem dataItem) {
+                        LOGD(TAG, "Sending image was successful: " + dataItem);
+                    }
+                });
     }
 
     @WorkerThread
@@ -301,7 +302,6 @@
 
             for (Node node : nodes) {
                 results.add(node.getId());
-
             }
 
         } catch (ExecutionException exception) {
@@ -314,18 +314,14 @@
         return results;
     }
 
-    /**
-     * As simple wrapper around Log.d
-     */
+    /** As simple wrapper around Log.d */
     private static void LOGD(final String tag, String message) {
         if (Log.isLoggable(tag, Log.DEBUG)) {
             Log.d(tag, message);
         }
     }
 
-    /**
-     * A View Adapter for presenting the Event objects in a list
-     */
+    /** A View Adapter for presenting the Event objects in a list */
     private static class DataItemAdapter extends ArrayAdapter<Event> {
 
         private final Context mContext;
@@ -340,8 +336,8 @@
             ViewHolder holder;
             if (convertView == null) {
                 holder = new ViewHolder();
-                LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
-                        Context.LAYOUT_INFLATER_SERVICE);
+                LayoutInflater inflater =
+                        (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                 convertView = inflater.inflate(android.R.layout.two_line_list_item, null);
                 convertView.setTag(holder);
                 holder.text1 = (TextView) convertView.findViewById(android.R.id.text1);
@@ -384,9 +380,7 @@
         }
     }
 
-    /**
-     * Generates a DataItem based on an incrementing count.
-     */
+    /** Generates a DataItem based on an incrementing count. */
     private class DataItemGenerator implements Runnable {
 
         private int count = 0;
diff --git a/wearable/wear/DataLayer/Wearable/src/main/AndroidManifest.xml b/wearable/wear/DataLayer/Wearable/src/main/AndroidManifest.xml
index 2bc5f4c..5e967aa 100644
--- a/wearable/wear/DataLayer/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/DataLayer/Wearable/src/main/AndroidManifest.xml
@@ -17,8 +17,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.example.android.wearable.datalayer" >
 
-    <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="25" />
+    <uses-sdk android:minSdkVersion="23"
+              android:targetSdkVersion="26" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
@@ -61,4 +61,4 @@
             </intent-filter>
         </activity>
     </application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/CustomRecyclerAdapter.java b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/CustomRecyclerAdapter.java
new file mode 100644
index 0000000..2e46eea
--- /dev/null
+++ b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/CustomRecyclerAdapter.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.wearable.datalayer;
+
+import static com.example.android.wearable.datalayer.DataLayerScreen.TYPE_CAPABILITY_DISCOVERY;
+import static com.example.android.wearable.datalayer.DataLayerScreen.TYPE_EVENT_LOGGING;
+import static com.example.android.wearable.datalayer.DataLayerScreen.TYPE_IMAGE_ASSET;
+
+import android.graphics.Bitmap;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.support.wear.widget.WearableRecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.example.android.wearable.datalayer.DataLayerScreen.DataLayerScreenData;
+import com.example.android.wearable.datalayer.DataLayerScreen.EventLoggingData;
+import com.example.android.wearable.datalayer.DataLayerScreen.ImageAssetData;
+
+import java.util.ArrayList;
+
+/**
+ * Populates a {@link WearableRecyclerView}.
+ *
+ * <p>Provides a custom {@link ViewHolder} for each unique row associated with a feature from the
+ * Data Layer APIs (one for transferring images, one for event logging, and one for checking
+ * capabilities). Data for each {@link ViewHolder} populated by {@link DataLayerScreen}.
+ */
+public class CustomRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+
+    private static final String TAG = "CustomRecyclerAdapter";
+
+    private ArrayList<DataLayerScreenData> mDataSet;
+
+    public CustomRecyclerAdapter(ArrayList<DataLayerScreenData> dataSet) {
+        mDataSet = dataSet;
+    }
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
+        Log.d(TAG, "onCreateViewHolder(): viewType: " + viewType);
+
+        RecyclerView.ViewHolder viewHolder = null;
+
+        switch (viewType) {
+            case TYPE_IMAGE_ASSET:
+                viewHolder =
+                        new ImageAssetViewHolder(
+                                LayoutInflater.from(viewGroup.getContext())
+                                        .inflate(
+                                                R.layout.recycler_row_image_asset,
+                                                viewGroup,
+                                                false));
+                break;
+
+            case TYPE_EVENT_LOGGING:
+                viewHolder =
+                        new EventLoggingViewHolder(
+                                LayoutInflater.from(viewGroup.getContext())
+                                        .inflate(
+                                                R.layout.recycler_row_event_logging,
+                                                viewGroup,
+                                                false));
+                break;
+
+            case TYPE_CAPABILITY_DISCOVERY:
+                viewHolder =
+                        new CapabilityDiscoveryViewHolder(
+                                LayoutInflater.from(viewGroup.getContext())
+                                        .inflate(
+                                                R.layout.recycler_row_capability_discovery,
+                                                viewGroup,
+                                                false));
+                break;
+        }
+
+        return viewHolder;
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
+        Log.d(TAG, "Element " + position + " set.");
+
+        switch (viewHolder.getItemViewType()) {
+            case TYPE_IMAGE_ASSET:
+                ImageAssetData imageAssetData = (ImageAssetData) mDataSet.get(position);
+
+                ImageAssetViewHolder imageAssetViewHolder = (ImageAssetViewHolder) viewHolder;
+                imageAssetViewHolder.setBackgroundImage(imageAssetData.getBitmap());
+                break;
+
+            case TYPE_EVENT_LOGGING:
+                EventLoggingData eventLoggingData = (EventLoggingData) mDataSet.get(position);
+
+                EventLoggingViewHolder eventLoggingViewHolder = (EventLoggingViewHolder) viewHolder;
+
+                String log = eventLoggingData.getLog();
+
+                if (log.length() > 0) {
+                    eventLoggingViewHolder.logDataLayerInformation(eventLoggingData.getLog());
+                }
+                break;
+
+            case TYPE_CAPABILITY_DISCOVERY:
+                // This view never changes, as it contains just two buttons that trigger
+                // capabilities requests to other devices.
+                break;
+        }
+    }
+
+    @Override
+    public int getItemCount() {
+        return mDataSet.size();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        DataLayerScreenData dataLayerScreenData = mDataSet.get(position);
+        return dataLayerScreenData.getType();
+    }
+
+    private int findItemIndex(@NonNull int assetType) {
+
+        for (int index = 0; index < mDataSet.size(); index++) {
+            if (mDataSet.get(index).getType() == assetType) {
+                return index;
+            }
+        }
+        return -1;
+    }
+
+    public void appendToDataEventLog(@NonNull String eventName, @NonNull String details) {
+        int index = findItemIndex(TYPE_EVENT_LOGGING);
+
+        if (index > -1) {
+            EventLoggingData dataItemType = (EventLoggingData) mDataSet.get(index);
+            dataItemType.addEventLog(eventName, details);
+
+            notifyItemChanged(index);
+        }
+    }
+
+    public int setImageAsset(Bitmap bitmap) {
+
+        int index = findItemIndex(TYPE_IMAGE_ASSET);
+
+        if ((index > -1) && (bitmap != null)) {
+            ImageAssetData imageAssetData = (ImageAssetData) mDataSet.get(index);
+            imageAssetData.setBitmap(bitmap);
+            notifyItemChanged(index);
+
+            return index;
+
+        } else {
+            return -1;
+        }
+    }
+
+    /** ***** Classes representing custom {@link ViewHolder}. ****** */
+
+    /**
+     * Displays {@link Bitmap} passed from other devices via the {@link
+     * com.google.android.gms.wearable.Asset} API.
+     */
+    public static class ImageAssetViewHolder extends RecyclerView.ViewHolder {
+
+        private final ImageView mImageView;
+
+        public ImageAssetViewHolder(View view) {
+            super(view);
+            mImageView = view.findViewById(R.id.image);
+        }
+
+        public void setBackgroundImage(Bitmap bitmap) {
+            mImageView.setImageBitmap(bitmap);
+        }
+    }
+
+    /**
+     * Displays text log of data passed from other devices via the {@link
+     * com.google.android.gms.wearable.MessageClient} API.
+     */
+    public static class EventLoggingViewHolder extends RecyclerView.ViewHolder {
+
+        private final TextView mIntroTextView;
+        private final TextView mDataLogTextView;
+
+        public EventLoggingViewHolder(View view) {
+            super(view);
+            mIntroTextView = view.findViewById(R.id.intro);
+            mDataLogTextView = view.findViewById(R.id.event_logging);
+        }
+
+        @Override
+        public String toString() {
+            return (String) mDataLogTextView.getText();
+        }
+
+        public void logDataLayerInformation(String log) {
+            mIntroTextView.setVisibility(View.INVISIBLE);
+            mDataLogTextView.setText(log);
+        }
+    }
+
+    /**
+     * Displays two buttons for querying device capabilities via {@link
+     * com.google.android.gms.wearable.CapabilityClient}.
+     */
+    public static class CapabilityDiscoveryViewHolder extends RecyclerView.ViewHolder {
+
+        public CapabilityDiscoveryViewHolder(View view) {
+            super(view);
+        }
+    }
+}
diff --git a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/DataLayerListenerService.java b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/DataLayerListenerService.java
index b9539a3..3df86ea 100644
--- a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/DataLayerListenerService.java
+++ b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/DataLayerListenerService.java
@@ -28,9 +28,7 @@
 import com.google.android.gms.wearable.Wearable;
 import com.google.android.gms.wearable.WearableListenerService;
 
-/**
- * Listens to DataItems and Messages from the local node.
- */
+/** Listens to DataItems and Messages from the local node. */
 public class DataLayerListenerService extends WearableListenerService {
 
     private static final String TAG = "DataLayerService";
@@ -60,19 +58,21 @@
                 // Send the rpc
                 // Instantiates clients without member variables, as clients are inexpensive to
                 // create. (They are cached and shared between GoogleApi instances.)
-                Task<Integer> sendMessageTask = Wearable.getMessageClient(this)
-                        .sendMessage(nodeId, DATA_ITEM_RECEIVED_PATH, payload);
+                Task<Integer> sendMessageTask =
+                        Wearable.getMessageClient(this)
+                                .sendMessage(nodeId, DATA_ITEM_RECEIVED_PATH, payload);
 
-                sendMessageTask.addOnCompleteListener(new OnCompleteListener<Integer>() {
-                    @Override
-                    public void onComplete(Task<Integer> task) {
-                        if (task.isSuccessful()) {
-                            Log.d(TAG, "Message sent successfully");
-                        } else {
-                            Log.d(TAG, "Message failed.");
-                        }
-                    }
-                });
+                sendMessageTask.addOnCompleteListener(
+                        new OnCompleteListener<Integer>() {
+                            @Override
+                            public void onComplete(Task<Integer> task) {
+                                if (task.isSuccessful()) {
+                                    Log.d(TAG, "Message sent successfully");
+                                } else {
+                                    Log.d(TAG, "Message failed.");
+                                }
+                            }
+                        });
             }
         }
     }
diff --git a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/DataLayerScreen.java b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/DataLayerScreen.java
new file mode 100644
index 0000000..23f444e
--- /dev/null
+++ b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/DataLayerScreen.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.wearable.datalayer;
+
+import android.graphics.Bitmap;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+
+/**
+ * Classes representing data used for each custom {@link ViewHolder} in {@link
+ * CustomRecyclerAdapter}.
+ */
+public class DataLayerScreen {
+
+    public static final int TYPE_IMAGE_ASSET = 0;
+    public static final int TYPE_EVENT_LOGGING = 1;
+    public static final int TYPE_CAPABILITY_DISCOVERY = 2;
+
+    /**
+     * All classes representing data for {@link ViewHolder} must implement this interface so {@link
+     * CustomRecyclerAdapter} knows what type of {@link ViewHolder} to inflate.
+     */
+    public interface DataLayerScreenData {
+        int getType();
+    }
+
+    /**
+     * Represents {@link Bitmap} passed to Wear device via {@link
+     * com.google.android.gms.wearable.Asset} data layer API.
+     */
+    public static class ImageAssetData implements DataLayerScreenData {
+
+        private Bitmap mBitmap;
+
+        ImageAssetData(Bitmap bitmap) {
+            mBitmap = bitmap;
+        }
+
+        @Override
+        public int getType() {
+            return TYPE_IMAGE_ASSET;
+        }
+
+        public Bitmap getBitmap() {
+            return mBitmap;
+        }
+
+        public void setBitmap(Bitmap bitmap) {
+            mBitmap = bitmap;
+        }
+    }
+
+    /**
+     * Represents message event logs passed to Wear device via {@link
+     * com.google.android.gms.wearable.MessageClient} data layer API.
+     */
+    public static class EventLoggingData implements DataLayerScreenData {
+
+        private StringBuilder mLogBuilder;
+
+        EventLoggingData() {
+            mLogBuilder = new StringBuilder();
+        }
+
+        @Override
+        public int getType() {
+            return TYPE_EVENT_LOGGING;
+        }
+
+        public String getLog() {
+            return mLogBuilder.toString();
+        }
+
+        public void addEventLog(String eventName, String data) {
+            mLogBuilder.append("\n" + eventName + "\n" + data);
+        }
+    }
+
+    /**
+     * No extra data needed as the {@link ViewHolder} only contains buttons checking capabilities of
+     * devices via the {@link com.google.android.gms.wearable.CapabilityClient} data layer API.
+     */
+    public static class CapabilityDiscoveryData implements DataLayerScreenData {
+
+        @Override
+        public int getType() {
+            return TYPE_CAPABILITY_DISCOVERY;
+        }
+    }
+}
diff --git a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/MainActivity.java b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
index 0044ca0..d212e51 100644
--- a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
+++ b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/MainActivity.java
@@ -16,26 +16,23 @@
 
 package com.example.android.wearable.datalayer;
 
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.support.wearable.view.DotsPageIndicator;
-import android.support.wearable.view.FragmentGridPagerAdapter;
-import android.support.wearable.view.GridViewPager;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.wear.ambient.AmbientModeSupport;
+import android.support.wear.widget.WearableRecyclerView;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
-import android.view.WindowManager;
 import android.widget.Toast;
 
-import com.example.android.wearable.datalayer.fragments.AssetFragment;
-import com.example.android.wearable.datalayer.fragments.DataFragment;
-import com.example.android.wearable.datalayer.fragments.DiscoveryFragment;
 import com.google.android.gms.tasks.OnSuccessListener;
 import com.google.android.gms.tasks.Task;
 import com.google.android.gms.tasks.Tasks;
@@ -51,6 +48,11 @@
 import com.google.android.gms.wearable.Node;
 import com.google.android.gms.wearable.Wearable;
 
+import com.example.android.wearable.datalayer.DataLayerScreen.CapabilityDiscoveryData;
+import com.example.android.wearable.datalayer.DataLayerScreen.DataLayerScreenData;
+import com.example.android.wearable.datalayer.DataLayerScreen.EventLoggingData;
+import com.example.android.wearable.datalayer.DataLayerScreen.ImageAssetData;
+
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -60,38 +62,71 @@
 import java.util.concurrent.ExecutionException;
 
 /**
- * The main activity with a view pager, containing three pages:<p/>
+ * Displays {@link WearableRecyclerView} with three main rows of data showing off various features
+ * of the Data Layer APIs:
+ *
+ * <p>
+ *
  * <ul>
- * <li>
- * Page 1: shows a list of DataItems received from the phone application
- * </li>
- * <li>
- * Page 2: shows the photo that is sent from the phone application
- * </li>
- * <li>
- * Page 3: includes two buttons to show the connected phone and watch devices
- * </li>
+ *   <li>Row 1: Shows a log of DataItems received from the phone application using {@link
+ *       MessageClient}
+ *   <li>Row 2: Shows a photo sent from the phone application using {@link DataClient}
+ *   <li>Row 3: Displays two buttons to check the connected phone and watch devices using the {@link
+ *       CapabilityClient}
  * </ul>
  */
-public class MainActivity extends Activity implements
-        DataClient.OnDataChangedListener,
-        MessageClient.OnMessageReceivedListener,
-        CapabilityClient.OnCapabilityChangedListener {
+public class MainActivity extends FragmentActivity
+        implements AmbientModeSupport.AmbientCallbackProvider,
+                DataClient.OnDataChangedListener,
+                MessageClient.OnMessageReceivedListener,
+                CapabilityClient.OnCapabilityChangedListener {
 
     private static final String TAG = "MainActivity";
+
     private static final String CAPABILITY_1_NAME = "capability_1";
     private static final String CAPABILITY_2_NAME = "capability_2";
 
-    private GridViewPager mPager;
-    private DataFragment mDataFragment;
-    private AssetFragment mAssetFragment;
+    ArrayList<DataLayerScreenData> mDataLayerScreenData;
+
+    private WearableRecyclerView mWearableRecyclerView;
+    private RecyclerView.LayoutManager mLayoutManager;
+    private CustomRecyclerAdapter mCustomRecyclerAdapter;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main_activity);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-        setupViews();
+
+        AmbientModeSupport.attach(this);
+
+        mWearableRecyclerView = findViewById(R.id.recycler_view);
+
+        // Aligns the first and last items on the list vertically centered on the screen.
+        mWearableRecyclerView.setEdgeItemsCenteringEnabled(true);
+
+        // Improves performance because we know changes in content do not change the layout size of
+        // the RecyclerView.
+        mWearableRecyclerView.setHasFixedSize(true);
+
+        mLayoutManager = new LinearLayoutManager(this);
+        mWearableRecyclerView.setLayoutManager(mLayoutManager);
+
+        mDataLayerScreenData = new ArrayList<>();
+
+        Bitmap defaultBitmap =
+                ((BitmapDrawable)
+                                ResourcesCompat.getDrawable(
+                                        getResources(), R.drawable.photo_placeholder, null))
+                        .getBitmap();
+
+        mDataLayerScreenData.add(new EventLoggingData());
+        mDataLayerScreenData.add(new ImageAssetData(defaultBitmap));
+        mDataLayerScreenData.add(new CapabilityDiscoveryData());
+
+        // Specifies an adapter (see also next example).
+        mCustomRecyclerAdapter = new CustomRecyclerAdapter(mDataLayerScreenData);
+
+        mWearableRecyclerView.setAdapter(mCustomRecyclerAdapter);
     }
 
     @Override
@@ -103,8 +138,7 @@
         Wearable.getDataClient(this).addListener(this);
         Wearable.getMessageClient(this).addListener(this);
         Wearable.getCapabilityClient(this)
-                .addListener(
-                        this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE);
+                .addListener(this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE);
     }
 
     @Override
@@ -116,6 +150,10 @@
         Wearable.getCapabilityClient(this).removeListener(this);
     }
 
+    /*
+     * Sends data to proper WearableRecyclerView logger row or if the item passed is an asset, sends
+     * to row displaying Bitmaps.
+     */
     @Override
     public void onDataChanged(DataEventBuffer dataEvents) {
         Log.d(TAG, "onDataChanged(): " + dataEvents);
@@ -125,27 +163,35 @@
                 String path = event.getDataItem().getUri().getPath();
                 if (DataLayerListenerService.IMAGE_PATH.equals(path)) {
                     DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
-                    Asset photoAsset = dataMapItem.getDataMap()
-                            .getAsset(DataLayerListenerService.IMAGE_KEY);
+                    Asset photoAsset =
+                            dataMapItem.getDataMap().getAsset(DataLayerListenerService.IMAGE_KEY);
                     // Loads image on background thread.
                     new LoadBitmapAsyncTask().execute(photoAsset);
 
                 } else if (DataLayerListenerService.COUNT_PATH.equals(path)) {
                     Log.d(TAG, "Data Changed for COUNT_PATH");
-                    mDataFragment.appendItem("DataItem Changed", event.getDataItem().toString());
+                    mCustomRecyclerAdapter.appendToDataEventLog(
+                            "DataItem Changed", event.getDataItem().toString());
                 } else {
                     Log.d(TAG, "Unrecognized path: " + path);
                 }
 
             } else if (event.getType() == DataEvent.TYPE_DELETED) {
-                mDataFragment.appendItem("DataItem Deleted", event.getDataItem().toString());
+                mCustomRecyclerAdapter.appendToDataEventLog(
+                        "DataItem Deleted", event.getDataItem().toString());
+
             } else {
-                mDataFragment.appendItem("Unknown data event type", "Type = " + event.getType());
+                mCustomRecyclerAdapter.appendToDataEventLog(
+                        "Unknown data event type", "Type = " + event.getType());
             }
         }
     }
 
-    public void onClicked(View view) {
+    /*
+     * Triggered directly from buttons in recycler_row_capability_discovery.xml to check
+     * capabilities of connected devices.
+     */
+    public void onCapabilityDiscoveryButtonClicked(View view) {
         switch (view.getId()) {
             case R.id.capability_2_btn:
                 showNodes(CAPABILITY_2_NAME);
@@ -158,45 +204,51 @@
         }
     }
 
+    /*
+     * Sends data to proper WearableRecyclerView logger row.
+     */
     @Override
     public void onMessageReceived(MessageEvent event) {
         Log.d(TAG, "onMessageReceived: " + event);
-        mDataFragment.appendItem("Message", event.toString());
+        mCustomRecyclerAdapter.appendToDataEventLog("Message", event.toString());
     }
 
+    /*
+     * Sends data to proper WearableRecyclerView logger row.
+     */
     @Override
     public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
         Log.d(TAG, "onCapabilityChanged: " + capabilityInfo);
-        mDataFragment.appendItem("onCapabilityChanged", capabilityInfo.toString());
+        mCustomRecyclerAdapter.appendToDataEventLog(
+                "onCapabilityChanged", capabilityInfo.toString());
     }
 
-    /**
-     * Find the connected nodes that provide at least one of the given capabilities
-     */
+    /** Find the connected nodes that provide at least one of the given capabilities. */
     private void showNodes(final String... capabilityNames) {
 
         Task<Map<String, CapabilityInfo>> capabilitiesTask =
                 Wearable.getCapabilityClient(this)
                         .getAllCapabilities(CapabilityClient.FILTER_REACHABLE);
 
-        capabilitiesTask.addOnSuccessListener(new OnSuccessListener<Map<String, CapabilityInfo>>() {
-            @Override
-            public void onSuccess(Map<String, CapabilityInfo> capabilityInfoMap) {
-                Set<Node> nodes = new HashSet<>();
+        capabilitiesTask.addOnSuccessListener(
+                new OnSuccessListener<Map<String, CapabilityInfo>>() {
+                    @Override
+                    public void onSuccess(Map<String, CapabilityInfo> capabilityInfoMap) {
+                        Set<Node> nodes = new HashSet<>();
 
-                if (capabilityInfoMap.isEmpty()) {
-                    showDiscoveredNodes(nodes);
-                    return;
-                }
-                for (String capabilityName : capabilityNames) {
-                    CapabilityInfo capabilityInfo = capabilityInfoMap.get(capabilityName);
-                    if (capabilityInfo != null) {
-                        nodes.addAll(capabilityInfo.getNodes());
+                        if (capabilityInfoMap.isEmpty()) {
+                            showDiscoveredNodes(nodes);
+                            return;
+                        }
+                        for (String capabilityName : capabilityNames) {
+                            CapabilityInfo capabilityInfo = capabilityInfoMap.get(capabilityName);
+                            if (capabilityInfo != null) {
+                                nodes.addAll(capabilityInfo.getNodes());
+                            }
+                        }
+                        showDiscoveredNodes(nodes);
                     }
-                }
-                showDiscoveredNodes(nodes);
-            }
-        });
+                });
     }
 
     private void showDiscoveredNodes(Set<Node> nodes) {
@@ -204,69 +256,21 @@
         for (Node node : nodes) {
             nodesList.add(node.getDisplayName());
         }
-        Log.d(TAG, "Connected Nodes: " + (nodesList.isEmpty()
-                ? "No connected device was found for the given capabilities"
-                : TextUtils.join(",", nodesList)));
+        Log.d(
+                TAG,
+                "Connected Nodes: "
+                        + (nodesList.isEmpty()
+                                ? "No connected device was found for the given capabilities"
+                                : TextUtils.join(",", nodesList)));
         String msg;
         if (!nodesList.isEmpty()) {
-            msg = getString(R.string.connected_nodes,
-                    TextUtils.join(", ", nodesList));
+            msg = getString(R.string.connected_nodes, TextUtils.join(", ", nodesList));
         } else {
             msg = getString(R.string.no_device);
         }
         Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
     }
 
-    private void setupViews() {
-        mPager = (GridViewPager) findViewById(R.id.pager);
-        mPager.setOffscreenPageCount(2);
-        DotsPageIndicator dotsPageIndicator = (DotsPageIndicator) findViewById(R.id.page_indicator);
-        dotsPageIndicator.setDotSpacing((int) getResources().getDimension(R.dimen.dots_spacing));
-        dotsPageIndicator.setPager(mPager);
-        mDataFragment = new DataFragment();
-        mAssetFragment = new AssetFragment();
-        DiscoveryFragment discoveryFragment = new DiscoveryFragment();
-        List<Fragment> pages = new ArrayList<>();
-        pages.add(mDataFragment);
-        pages.add(mAssetFragment);
-        pages.add(discoveryFragment);
-        final MyPagerAdapter adapter = new MyPagerAdapter(getFragmentManager(), pages);
-        mPager.setAdapter(adapter);
-    }
-
-    /**
-     * Switches to the page {@code index}. The first page has index 0.
-     */
-    private void moveToPage(int index) {
-        mPager.setCurrentItem(0, index, true);
-    }
-
-    private class MyPagerAdapter extends FragmentGridPagerAdapter {
-
-        private List<Fragment> mFragments;
-
-        public MyPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
-            super(fm);
-            mFragments = fragments;
-        }
-
-        @Override
-        public int getRowCount() {
-            return 1;
-        }
-
-        @Override
-        public int getColumnCount(int row) {
-            return mFragments == null ? 0 : mFragments.size();
-        }
-
-        @Override
-        public Fragment getFragment(int row, int column) {
-            return mFragments.get(column);
-        }
-
-    }
-
     /*
      * Extracts {@link android.graphics.Bitmap} data from the
      * {@link com.google.android.gms.wearable.Asset}
@@ -321,9 +325,45 @@
 
             if (bitmap != null) {
                 Log.d(TAG, "Setting background image on second page..");
-                moveToPage(1);
-                mAssetFragment.setBackgroundImage(bitmap);
+                int imageAssetItemIndex = mCustomRecyclerAdapter.setImageAsset(bitmap);
+
+                // Moves RecyclerView to appropriate row to show new image sent over.
+                if (imageAssetItemIndex > -1) {
+                    mWearableRecyclerView.scrollToPosition(imageAssetItemIndex);
+                    ;
+                }
             }
         }
     }
+
+    @Override
+    public AmbientModeSupport.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    /** Customizes appearance for Ambient mode. (We don't do anything minus default.) */
+    private class MyAmbientCallback extends AmbientModeSupport.AmbientCallback {
+        /** Prepares the UI for ambient mode. */
+        @Override
+        public void onEnterAmbient(Bundle ambientDetails) {
+            super.onEnterAmbient(ambientDetails);
+        }
+
+        /**
+         * Updates the display in ambient mode on the standard interval. Since we're using a custom
+         * refresh cycle, this method does NOT update the data in the display. Rather, this method
+         * simply updates the positioning of the data in the screen to avoid burn-in, if the display
+         * requires it.
+         */
+        @Override
+        public void onUpdateAmbient() {
+            super.onUpdateAmbient();
+        }
+
+        /** Restores the UI to active (non-ambient) mode. */
+        @Override
+        public void onExitAmbient() {
+            super.onExitAmbient();
+        }
+    }
 }
diff --git a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/fragments/AssetFragment.java b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/fragments/AssetFragment.java
deleted file mode 100644
index 312b086..0000000
--- a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/fragments/AssetFragment.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.wearable.datalayer.fragments;
-
-import android.app.Fragment;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-
-import com.example.android.wearable.datalayer.R;
-
-/**
- * A simple fragment that shows a (photo) asset received from the phone.
- */
-public class AssetFragment extends Fragment {
-
-    private ImageView mPhoto;
-
-    @Nullable
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.asset_fragment, container, false);
-        mPhoto = view.findViewById(R.id.photo);
-        return view;
-    }
-
-    public void setBackgroundImage(Bitmap bitmap) {
-        mPhoto.setImageBitmap(bitmap);
-    }
-}
diff --git a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/fragments/DataFragment.java b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/fragments/DataFragment.java
deleted file mode 100644
index c8457fc..0000000
--- a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/fragments/DataFragment.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.wearable.datalayer.fragments;
-
-import android.app.Fragment;
-import android.content.Context;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.example.android.wearable.datalayer.R;
-
-/**
- * A fragment that shows a list of DataItems received from the phone
- */
-public class DataFragment extends Fragment {
-
-    private DataItemAdapter mDataItemListAdapter;
-    private TextView mIntroText;
-    private boolean mInitialized;
-
-    @Nullable
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.data_fragment, container, false);
-        ListView dataItemList = view.findViewById(R.id.dataItem_list);
-        mIntroText = view.findViewById(R.id.intro);
-        mDataItemListAdapter = new DataItemAdapter(getActivity(),
-                android.R.layout.simple_list_item_1);
-        dataItemList.setAdapter(mDataItemListAdapter);
-        mInitialized = true;
-        return view;
-    }
-
-    public void appendItem(String title, String text) {
-        if (!mInitialized) {
-            return;
-        }
-        mIntroText.setVisibility(View.INVISIBLE);
-        mDataItemListAdapter.add(new Event(title, text));
-    }
-
-    private static class DataItemAdapter extends ArrayAdapter<Event> {
-
-        private final Context mContext;
-
-        public DataItemAdapter(Context context, int unusedResource) {
-            super(context, unusedResource);
-            mContext = context;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            ViewHolder holder;
-            if (convertView == null) {
-                holder = new ViewHolder();
-                LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
-                        Context.LAYOUT_INFLATER_SERVICE);
-                convertView = inflater.inflate(android.R.layout.two_line_list_item, null);
-                convertView.setTag(holder);
-                holder.text1 = convertView.findViewById(android.R.id.text1);
-                holder.text2 = convertView.findViewById(android.R.id.text2);
-            } else {
-                holder = (ViewHolder) convertView.getTag();
-            }
-            Event event = getItem(position);
-            holder.text1.setText(event.title);
-            holder.text2.setText(event.text);
-            return convertView;
-        }
-
-        private class ViewHolder {
-
-            TextView text1;
-            TextView text2;
-        }
-    }
-
-    private class Event {
-
-        String title;
-        String text;
-
-        public Event(String title, String text) {
-            this.title = title;
-            this.text = text;
-        }
-    }
-}
diff --git a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/fragments/DiscoveryFragment.java b/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/fragments/DiscoveryFragment.java
deleted file mode 100644
index 90b4b06..0000000
--- a/wearable/wear/DataLayer/Wearable/src/main/java/com/example/android/wearable/datalayer/fragments/DiscoveryFragment.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.wearable.datalayer.fragments;
-
-import android.app.Fragment;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.example.android.wearable.datalayer.R;
-
-/**
- * A simple fragment with two buttons to show connected phones and watches
- */
-public class DiscoveryFragment extends Fragment {
-
-    @Nullable
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        return inflater.inflate(R.layout.discovery_fragment, container, false);
-    }
-}
diff --git a/wearable/wear/DataLayer/Wearable/src/main/res/layout/data_fragment.xml b/wearable/wear/DataLayer/Wearable/src/main/res/layout/data_fragment.xml
deleted file mode 100644
index efbbe9c..0000000
--- a/wearable/wear/DataLayer/Wearable/src/main/res/layout/data_fragment.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/layout"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:background="@color/black">
-
-    <ListView
-        android:id="@+id/dataItem_list"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:transcriptMode="alwaysScroll"/>
-
-    <TextView
-        android:id="@+id/intro"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:textSize="20sp"
-        android:layout_marginLeft="16dp"
-        android:layout_marginRight="16dp"
-        android:gravity="center"
-        android:fontFamily="sans-serif-condensed-light"
-        android:text="@string/intro" />
-</RelativeLayout>
diff --git a/wearable/wear/DataLayer/Wearable/src/main/res/layout/main_activity.xml b/wearable/wear/DataLayer/Wearable/src/main/res/layout/main_activity.xml
index 4608e4b..a7a3430 100644
--- a/wearable/wear/DataLayer/Wearable/src/main/res/layout/main_activity.xml
+++ b/wearable/wear/DataLayer/Wearable/src/main/res/layout/main_activity.xml
@@ -13,26 +13,16 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:background="@color/white">
 
-    <android.support.wearable.view.GridViewPager
-        android:id="@+id/pager"
+
+    <android.support.wear.widget.WearableRecyclerView
+        android:id="@+id/recycler_view"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
+        android:layout_height="match_parent">
 
-    <android.support.wearable.view.DotsPageIndicator
-        android:id="@+id/page_indicator"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:layout_centerHorizontal="true"
-        android:layout_marginBottom="10dp"
-        android:padding="5dp"
-        android:background="@drawable/rounded_background">
-    </android.support.wearable.view.DotsPageIndicator>
-
+    </android.support.wear.widget.WearableRecyclerView>
 </RelativeLayout>
diff --git a/wearable/wear/DataLayer/Wearable/src/main/res/layout/discovery_fragment.xml b/wearable/wear/DataLayer/Wearable/src/main/res/layout/recycler_row_capability_discovery.xml
similarity index 76%
rename from wearable/wear/DataLayer/Wearable/src/main/res/layout/discovery_fragment.xml
rename to wearable/wear/DataLayer/Wearable/src/main/res/layout/recycler_row_capability_discovery.xml
index 5cd247c..6e52780 100644
--- a/wearable/wear/DataLayer/Wearable/src/main/res/layout/discovery_fragment.xml
+++ b/wearable/wear/DataLayer/Wearable/src/main/res/layout/recycler_row_capability_discovery.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- Copyright (C) 2018 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -20,12 +20,14 @@
     android:layout_height="match_parent">
 
     <View
-        android:layout_width="fill_parent"
+        android:layout_width="match_parent"
         android:layout_height="1dp"
         android:id="@+id/center"
         android:visibility="invisible"
         android:layout_centerVertical="true" />
 
+    <!-- Method triggered directly in MainActivity.java (onCapabilityDiscoveryButtonClicked()),
+         not in CustomRecyclerAdapter.java. -->
     <Button
         android:id="@+id/capability_2_btn"
         android:text="@string/capability_2_notification"
@@ -34,8 +36,10 @@
         android:layout_above="@id/center"
         android:layout_centerHorizontal="true"
         android:textSize="12sp"
-        android:onClick="onClicked" />
+        android:onClick="onCapabilityDiscoveryButtonClicked" />
 
+    <!-- Method triggered directly in MainActivity.java (onCapabilityDiscoveryButtonClicked()),
+         not in CustomRecyclerAdapter.java. -->
     <Button
         android:id="@+id/capabilities_1_and_2_btn"
         android:text="@string/capabilities_1_and_2_notification"
@@ -45,6 +49,6 @@
         android:textSize="10sp"
         android:layout_alignEnd="@+id/capability_2_btn"
         android:layout_alignStart="@+id/capability_2_btn"
-        android:onClick="onClicked" />
+        android:onClick="onCapabilityDiscoveryButtonClicked" />
 
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/wearable/wear/DataLayer/Wearable/src/main/res/layout/recycler_row_event_logging.xml b/wearable/wear/DataLayer/Wearable/src/main/res/layout/recycler_row_event_logging.xml
new file mode 100644
index 0000000..e010d96
--- /dev/null
+++ b/wearable/wear/DataLayer/Wearable/src/main/res/layout/recycler_row_event_logging.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<android.support.wear.widget.BoxInsetLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/black">
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        app:boxedEdges="all">
+
+        <TextView
+            android:id="@+id/intro"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:textSize="20sp"
+            android:gravity="center"
+            android:fontFamily="sans-serif-condensed-light"
+            android:text="@string/intro"/>
+
+        <TextView
+            android:id="@+id/event_logging"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:transcriptMode="alwaysScroll"/>
+    </FrameLayout>
+</android.support.wear.widget.BoxInsetLayout>
diff --git a/wearable/wear/DataLayer/Wearable/src/main/res/layout/asset_fragment.xml b/wearable/wear/DataLayer/Wearable/src/main/res/layout/recycler_row_image_asset.xml
similarity index 72%
rename from wearable/wear/DataLayer/Wearable/src/main/res/layout/asset_fragment.xml
rename to wearable/wear/DataLayer/Wearable/src/main/res/layout/recycler_row_image_asset.xml
index 3c5f7b1..420df5c 100644
--- a/wearable/wear/DataLayer/Wearable/src/main/res/layout/asset_fragment.xml
+++ b/wearable/wear/DataLayer/Wearable/src/main/res/layout/recycler_row_image_asset.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- Copyright (C) 2018 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -17,13 +17,12 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/layout"
     android:orientation="vertical"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent">
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
 
     <ImageView
-        android:id="@+id/photo"
+        android:id="@+id/image"
         android:scaleType="centerCrop"
-        android:src="@drawable/photo_placeholder"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent" />
-</LinearLayout>
\ No newline at end of file
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/wearable/wear/DataLayer/gradle.properties b/wearable/wear/DataLayer/gradle.properties
new file mode 100644
index 0000000..0bc4294
--- /dev/null
+++ b/wearable/wear/DataLayer/gradle.properties
@@ -0,0 +1,20 @@
+
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Settings specified in this file will override any Gradle settings
+# configured through the IDE.
+
+# 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.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# 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/wearable/wear/DataLayer/template-params.xml b/wearable/wear/DataLayer/template-params.xml
index ba07ff6..cc43fa5 100644
--- a/wearable/wear/DataLayer/template-params.xml
+++ b/wearable/wear/DataLayer/template-params.xml
@@ -21,6 +21,8 @@
 
     <minSdk>18</minSdk>
     <targetSdkVersion>27</targetSdkVersion>
+
+    <minSdkVersionWear>23</minSdkVersionWear>
     <compileSdkVersionWear>26</compileSdkVersionWear>
     <targetSdkVersionWear>26</targetSdkVersionWear>
 
@@ -29,6 +31,8 @@
     <dependency>com.android.support:recyclerview-v7:27.1.1</dependency>
     <dependency>com.android.support:percent:27.1.1</dependency>
 
+    <dependency_wearable>com.android.support:wear:27.1.1</dependency_wearable>
+
     <dependency_wearable>com.android.support:recyclerview-v7:27.1.1</dependency_wearable>
     <dependency_wearable>com.android.support:percent:27.1.1</dependency_wearable>